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 <afs/param.h>
13 #include <sys/types.h>
16 #if defined(AFS_AIX_ENV)
18 #include <sys/statfs.h>
21 #endif /* AFS_AIX_ENV */
23 #include <sys/ioctl.h>
25 #include <afs/debug.h>
29 typedef off64_t osi_lloff_t;
30 #define osi_llseek lseek64
31 #else /* O_LARGEFILE */
32 #ifdef AFS_HAVE_LLSEEK
33 typedef offset_t osi_lloff_t;
34 #define osi_llseek llseek
35 #else /* AFS_HAVE_LLSEEK */
36 typedef off_t osi_lloff_t;
37 #define osi_llseek lseek
38 #endif /* AFS_HAVE_LLSEEK */
39 #endif /* O_LARGEFILE */
42 * This macro should be used inside assertions wherever offset/hyper
43 * conversion occur. A good compiler in a 64 bit environment will
44 * elide the entire statement if the offset type is 64 bits wide.
46 #define osi_hFitsInOff(ahyper, noff) \
47 ((sizeof(noff) == 4) ? hfitsin32(ahyper) : 1)
49 #define osi_h2off(ahyper, noff) \
50 ((sizeof(noff) == 4) \
51 ? ((noff) = (osi_lloff_t)hgetlo(ahyper))\
52 : ((noff) = ((osi_lloff_t)hgethi(ahyper)<<32) | (osi_lloff_t)hgetlo(ahyper)))
54 #define osi_off2h(noff, ahyper) \
55 ((sizeof(noff) == 4) \
56 ? (hset32(ahyper, (int)noff)) \
57 : (hset64(ahyper, (int)((noff>>32)&0xffffffff), ((int)noff&0xffffffff))))
60 /************ End of osi wrappers ***********************************/
62 /* Implementation of user space device I/O for regular POSIX files. */
64 static int usd_FileRead(
70 int fd = (int)(usd->handle);
73 got = read(fd, buf, nbytes);
84 static int usd_FileWrite(
90 int fd = (int)(usd->handle);
93 sent = write(fd, buf, nbytes);
104 extern osi_lloff_t osi_llseek(int, osi_lloff_t, int);
106 static int usd_FileSeek(
110 afs_hyper_t *curOffP)
112 int fd = (int)(usd->handle);
115 if (!osi_hFitsInOff(reqOff, lloff))
118 osi_h2off(reqOff, lloff);
119 lloff = osi_llseek(fd, lloff, whence);
120 if (lloff == (((osi_lloff_t)0) - 1))
123 osi_off2h(lloff, *curOffP);
128 static int usd_FileIoctl(usd_handle_t usd, int req, void *arg)
130 int fd = (int)(usd->handle);
133 #else /* O_LARGEFILE */
135 #endif /* O_LARGEFILE */
137 struct statfs fsinfo; /* AIX stat structure doesn't have st_blksize */
138 #endif /* AFS_AIX_ENV */
144 case USD_IOCTL_GETBLKSIZE:
146 code = fstatfs(fd, &fsinfo);
148 *((long *)arg) = (long)4096;
152 #endif /* AFS_AIX_ENV */
153 case USD_IOCTL_GETTYPE:
154 case USD_IOCTL_GETDEV:
155 case USD_IOCTL_GETSIZE:
157 code = fstat64(fd, &info);
158 #else /* O_LARGEFILE */
159 code = fstat(fd, &info);
160 #endif /* O_LARGEFILE */
167 case USD_IOCTL_GETTYPE:
168 *(int *)arg = info.st_mode & S_IFMT;
170 case USD_IOCTL_GETDEV:
171 if (!(S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)))
172 return ENODEV; /* not a device */
173 *(dev_t *)arg = info.st_rdev;
175 case USD_IOCTL_GETSIZE:
176 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode))
177 return ENOTTY; /* shouldn't be a device */
178 osi_off2h(info.st_size, *(afs_hyper_t *)arg);
180 case USD_IOCTL_GETFULLNAME:
181 *(char **)arg = usd->fullPathName;
184 case USD_IOCTL_SETSIZE:
186 /* We could just use ftruncate in all cases. (This even works on AIX;
187 * I tried it). -blake 931118 */
189 /* However, I'm pretty sure this doesn't work on Ultrix so I am
190 * unsure about OSF/1 and HP/UX. 931118 */
192 size = *(afs_hyper_t *)arg;
193 if (!osi_hFitsInOff(size, off))
195 osi_h2off(size, off);
197 code = ftruncate64 (fd, off);
198 #else /* O_LARGEFILE */
199 code = ftruncate (fd, off);
200 #endif /* O_LARGEFILE */
205 case USD_IOCTL_TAPEOPERATION:
207 usd_tapeop_t *tapeOpp = (usd_tapeop_t *)arg;
208 #if defined(AFS_AIX_ENV)
209 struct stop os_tapeop;
211 if (tapeOpp->tp_op == USDTAPE_WEOF) {
212 os_tapeop.st_op = STWEOF;
213 } else if (tapeOpp->tp_op == USDTAPE_REW) {
214 os_tapeop.st_op = STREW;
215 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
216 os_tapeop.st_op = STFSF;
217 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
218 os_tapeop.st_op = STRSF;
219 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
221 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
224 /* unsupported tape operation */
227 os_tapeop.st_count = tapeOpp->tp_count;
229 code = ioctl(fd, STIOCTOP, &os_tapeop);
231 struct mtop os_tapeop;
233 if (tapeOpp->tp_op == USDTAPE_WEOF) {
234 os_tapeop.mt_op = MTWEOF;
235 } else if (tapeOpp->tp_op == USDTAPE_REW) {
236 os_tapeop.mt_op = MTREW;
237 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
238 os_tapeop.mt_op = MTFSF;
239 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
240 os_tapeop.mt_op = MTBSF;
241 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
243 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
246 /* unsupported tape operation */
249 os_tapeop.mt_count = tapeOpp->tp_count;
251 code = ioctl(fd, MTIOCTOP, &os_tapeop);
252 #endif /* AFS_AIX_ENV */
262 case USD_IOCTL_GETBLKSIZE:
263 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)) {
264 *((long *)arg) = (long)4096;
268 *((long *)arg) = (long)fsinfo.f_bsize;
269 #else /* AFS_AIX_ENV */
270 *((long *)arg) = (long)info.st_blksize;
271 #endif /* AFS_AIX_ENV */
280 static int usd_FileClose(usd_handle_t usd)
282 int fd = (int)(usd->handle);
286 /* I can't really believe this is necessary. On the one hand the user
287 * space code always uses character devices, which aren't supposed to do
288 * any buffering. On the other, I very much doubt fsyncing a regular file
289 * being salvaged is ever necessary. But the salvager used to do this
290 * before returning, so... */
292 if (usd->openFlags & (O_WRONLY|O_RDWR)) {
294 code = usd_FileIoctl(usd, USD_IOCTL_GETTYPE, &mode);
298 /* on AIX3.1 can't fsync raw disk device */
313 if (usd->fullPathName)
314 free(usd->fullPathName);
320 static int usd_FileOpen(
334 oflags = (flags & USD_OPEN_RDWR) ? O_RDWR : O_RDONLY;
336 if (flags & USD_OPEN_SYNC)
339 if (flags & USD_OPEN_CREATE)
343 fd = open64(path, oflags, mode);
344 #else /* O_LARGEFILE */
345 fd = open(path, oflags, mode);
346 #endif /* O_LARGEFILE */
350 usd = (usd_handle_t) malloc(sizeof(*usd));
351 bzero(usd, sizeof(*usd));
352 usd->handle = (void *)fd;
353 usd->read = usd_FileRead;
354 usd->write = usd_FileWrite;
355 usd->seek = usd_FileSeek;
356 usd->ioctl = usd_FileIoctl;
357 usd->close = usd_FileClose;
358 usd->fullPathName = (char *)malloc(strlen(path)+1);
359 strcpy(usd->fullPathName, path);
360 usd->openFlags = flags;
363 if (flags & (USD_OPEN_RLOCK|USD_OPEN_WLOCK)) {
366 #else /* O_LARGEFILE */
368 #endif /* O_LARGEFILE */
370 /* make sure both lock bits aren't set */
371 assert(~flags & (USD_OPEN_RLOCK|USD_OPEN_WLOCK));
373 fl.l_type = ((flags & USD_OPEN_RLOCK) ? F_RDLCK : F_WRLCK);
374 fl.l_whence = SEEK_SET;
375 fl.l_start = (osi_lloff_t)0;
376 fl.l_len = (osi_lloff_t)0; /* whole file */
378 code = fcntl(fd, F_SETLK64, &fl);
379 #else /* O_LARGEFILE */
380 code = fcntl(fd, F_SETLK, &fl);
381 #endif /* O_LARGEFILE */
385 /* If we're trying to obtain a write lock on a real disk, then the
386 * aggregate must not be attached by the kernel. If so, unlock it
388 * WARNING: The code to check for the above has been removed when this
389 * file was ported from DFS src. It should be put back if
390 * this library is used to access hard disks
394 if (code == 0 && usdP)
401 static int usd_FileDummyClose(usd_handle_t usd)
407 int usd_Open(const char *path, int oflag, int mode, usd_handle_t *usdP)
409 return usd_FileOpen(path, oflag, mode, usdP);
412 static int usd_FileStandardInput(
420 usd = (usd_handle_t) malloc(sizeof(*usd));
421 bzero(usd, sizeof(*usd));
422 usd->handle = (void *)((unsigned long)0);
423 usd->read = usd_FileRead;
424 usd->write = usd_FileWrite;
425 usd->seek = usd_FileSeek;
426 usd->ioctl = usd_FileIoctl;
427 usd->close = usd_FileDummyClose;
428 usd->fullPathName = "STDIN";
435 int usd_StandardInput(usd_handle_t *usdP)
437 return usd_FileStandardInput(usdP);
440 static int usd_FileStandardOutput(
448 usd = (usd_handle_t) malloc(sizeof(*usd));
449 bzero(usd, sizeof(*usd));
450 usd->handle = (void *)((unsigned long)1);
451 usd->read = usd_FileRead;
452 usd->write = usd_FileWrite;
453 usd->seek = usd_FileSeek;
454 usd->ioctl = usd_FileIoctl;
455 usd->close = usd_FileDummyClose;
456 usd->fullPathName = "STDOUT";
463 int usd_StandardOutput(usd_handle_t *usdP)
465 return usd_FileStandardOutput(usdP);