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>
18 #include <sys/types.h>
21 #if defined(AFS_AIX_ENV)
23 #include <sys/statfs.h>
26 #include <sys/ioccom.h>
28 #if defined(AFS_DUX40_ENV) || defined(AFS_OBSD_ENV) || defined(AFS_NBSD_ENV)
29 #include <sys/ioctl.h>
32 #endif /* AFS_AIX_ENV */
43 #include <afs/debug.h>
47 typedef off64_t osi_lloff_t;
48 #define osi_llseek lseek64
49 #else /* O_LARGEFILE */
50 #ifdef AFS_HAVE_LLSEEK
51 typedef offset_t osi_lloff_t;
52 #define osi_llseek llseek
53 #else /* AFS_HAVE_LLSEEK */
54 typedef off_t osi_lloff_t;
55 #define osi_llseek lseek
56 #endif /* AFS_HAVE_LLSEEK */
57 #endif /* O_LARGEFILE */
60 * This macro should be used inside assertions wherever offset/hyper
61 * conversion occur. A good compiler in a 64 bit environment will
62 * elide the entire statement if the offset type is 64 bits wide.
64 #define osi_hFitsInOff(ahyper, noff) \
65 ((sizeof(noff) == 4) ? hfitsin32(ahyper) : 1)
67 #define osi_h2off(ahyper, noff) \
68 ((sizeof(noff) == 4) \
69 ? ((noff) = (osi_lloff_t)hgetlo(ahyper))\
70 : ((noff) = ((osi_lloff_t)hgethi(ahyper)<<32) | (osi_lloff_t)hgetlo(ahyper)))
72 #define osi_off2h(noff, ahyper) \
73 ((sizeof(noff) == 4) \
74 ? (hset32(ahyper, (int)noff)) \
75 : (hset64(ahyper, (int)((noff>>32)&0xffffffff), ((int)noff&0xffffffff))))
78 /************ End of osi wrappers ***********************************/
80 /* Implementation of user space device I/O for regular POSIX files. */
83 usd_FileRead(usd_handle_t usd, char *buf, afs_uint32 nbytes,
86 int fd = (int)(usd->handle);
89 got = read(fd, buf, nbytes);
101 usd_FileWrite(usd_handle_t usd, char *buf, afs_uint32 nbytes,
104 int fd = (int)(usd->handle);
107 sent = write(fd, buf, nbytes);
118 extern osi_lloff_t osi_llseek(int, osi_lloff_t, int);
121 usd_FileSeek(usd_handle_t usd, afs_hyper_t reqOff, int whence,
122 afs_hyper_t * curOffP)
124 int fd = (int)(usd->handle);
127 if (!osi_hFitsInOff(reqOff, lloff))
130 osi_h2off(reqOff, lloff);
131 lloff = osi_llseek(fd, lloff, whence);
132 if (lloff == (((osi_lloff_t) 0) - 1))
135 osi_off2h(lloff, *curOffP);
141 usd_FileIoctl(usd_handle_t usd, int req, void *arg)
143 int fd = (int)(usd->handle);
146 #else /* O_LARGEFILE */
148 #endif /* O_LARGEFILE */
150 struct statfs fsinfo; /* AIX stat structure doesn't have st_blksize */
151 #endif /* AFS_AIX_ENV */
157 case USD_IOCTL_GETBLKSIZE:
159 code = fstatfs(fd, &fsinfo);
161 *((long *)arg) = (long)4096;
165 #endif /* AFS_AIX_ENV */
166 case USD_IOCTL_GETTYPE:
167 case USD_IOCTL_GETDEV:
168 case USD_IOCTL_GETSIZE:
170 code = fstat64(fd, &info);
171 #else /* O_LARGEFILE */
172 code = fstat(fd, &info);
173 #endif /* O_LARGEFILE */
180 case USD_IOCTL_GETTYPE:
181 *(int *)arg = info.st_mode & S_IFMT;
183 case USD_IOCTL_GETDEV:
184 if (!(S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)))
185 return ENODEV; /* not a device */
186 *(dev_t *) arg = info.st_rdev;
188 case USD_IOCTL_GETSIZE:
189 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode))
190 return ENOTTY; /* shouldn't be a device */
191 osi_off2h(info.st_size, *(afs_hyper_t *) arg);
193 case USD_IOCTL_GETFULLNAME:
194 *(char **)arg = usd->fullPathName;
197 case USD_IOCTL_SETSIZE:
199 /* We could just use ftruncate in all cases. (This even works on AIX;
200 * I tried it). -blake 931118 */
202 /* However, I'm pretty sure this doesn't work on Ultrix so I am
203 * unsure about OSF/1 and HP/UX. 931118 */
205 size = *(afs_hyper_t *) arg;
206 if (!osi_hFitsInOff(size, off))
208 osi_h2off(size, off);
210 code = ftruncate64(fd, off);
211 #else /* O_LARGEFILE */
212 code = ftruncate(fd, off);
213 #endif /* O_LARGEFILE */
218 case USD_IOCTL_TAPEOPERATION:
220 usd_tapeop_t *tapeOpp = (usd_tapeop_t *) arg;
221 #if defined(AFS_AIX_ENV)
222 struct stop os_tapeop;
224 if (tapeOpp->tp_op == USDTAPE_WEOF) {
225 os_tapeop.st_op = STWEOF;
226 } else if (tapeOpp->tp_op == USDTAPE_REW) {
227 os_tapeop.st_op = STREW;
228 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
229 os_tapeop.st_op = STFSF;
230 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
231 os_tapeop.st_op = STRSF;
232 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
234 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
237 /* unsupported tape operation */
240 os_tapeop.st_count = tapeOpp->tp_count;
242 code = ioctl(fd, STIOCTOP, &os_tapeop);
244 struct mtop os_tapeop;
246 if (tapeOpp->tp_op == USDTAPE_WEOF) {
247 os_tapeop.mt_op = MTWEOF;
248 } else if (tapeOpp->tp_op == USDTAPE_REW) {
249 os_tapeop.mt_op = MTREW;
250 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
251 os_tapeop.mt_op = MTFSF;
252 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
253 os_tapeop.mt_op = MTBSF;
254 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
256 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
259 /* unsupported tape operation */
262 os_tapeop.mt_count = tapeOpp->tp_count;
264 code = ioctl(fd, MTIOCTOP, &os_tapeop);
265 #endif /* AFS_AIX_ENV */
275 case USD_IOCTL_GETBLKSIZE:
276 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)) {
277 *((long *)arg) = (long)4096;
281 *((long *)arg) = (long)fsinfo.f_bsize;
282 #else /* AFS_AIX_ENV */
283 *((long *)arg) = (long)info.st_blksize;
284 #endif /* AFS_AIX_ENV */
294 usd_FileClose(usd_handle_t usd)
296 int fd = (int)(usd->handle);
300 /* I can't really believe this is necessary. On the one hand the user
301 * space code always uses character devices, which aren't supposed to do
302 * any buffering. On the other, I very much doubt fsyncing a regular file
303 * being salvaged is ever necessary. But the salvager used to do this
304 * before returning, so... */
306 if (usd->openFlags & (O_WRONLY | O_RDWR)) {
308 code = usd_FileIoctl(usd, USD_IOCTL_GETTYPE, &mode);
309 if (code == 0 && S_ISBLK(mode)) {
319 if (usd->fullPathName)
320 free(usd->fullPathName);
327 usd_FileOpen(const char *path, int flags, int mode, usd_handle_t * usdP)
337 oflags = (flags & USD_OPEN_RDWR) ? O_RDWR : O_RDONLY;
339 #ifdef O_SYNC /* AFS_DARWIN_ENV XXX */
340 if (flags & USD_OPEN_SYNC)
344 if (flags & USD_OPEN_CREATE)
348 fd = open64(path, oflags | O_LARGEFILE, mode);
349 #else /* O_LARGEFILE */
350 fd = open(path, oflags, mode);
351 #endif /* O_LARGEFILE */
355 usd = (usd_handle_t) malloc(sizeof(*usd));
356 memset(usd, 0, sizeof(*usd));
357 usd->handle = (void *)fd;
358 usd->read = usd_FileRead;
359 usd->write = usd_FileWrite;
360 usd->seek = usd_FileSeek;
361 usd->ioctl = usd_FileIoctl;
362 usd->close = usd_FileClose;
363 usd->fullPathName = (char *)malloc(strlen(path) + 1);
364 strcpy(usd->fullPathName, path);
365 usd->openFlags = flags;
368 if (flags & (USD_OPEN_RLOCK | USD_OPEN_WLOCK)) {
371 #else /* O_LARGEFILE */
373 #endif /* O_LARGEFILE */
375 /* make sure both lock bits aren't set */
376 assert(~flags & (USD_OPEN_RLOCK | USD_OPEN_WLOCK));
378 fl.l_type = ((flags & USD_OPEN_RLOCK) ? F_RDLCK : F_WRLCK);
379 fl.l_whence = SEEK_SET;
380 fl.l_start = (osi_lloff_t) 0;
381 fl.l_len = (osi_lloff_t) 0; /* whole file */
383 code = fcntl(fd, F_SETLK64, &fl);
384 #else /* O_LARGEFILE */
385 code = fcntl(fd, F_SETLK, &fl);
386 #endif /* O_LARGEFILE */
390 /* If we're trying to obtain a write lock on a real disk, then the
391 * aggregate must not be attached by the kernel. If so, unlock it
393 * WARNING: The code to check for the above has been removed when this
394 * file was ported from DFS src. It should be put back if
395 * this library is used to access hard disks
399 if (code == 0 && usdP)
407 usd_FileDummyClose(usd_handle_t usd)
414 usd_Open(const char *path, int oflag, int mode, usd_handle_t * usdP)
416 return usd_FileOpen(path, oflag, mode, usdP);
420 usd_FileStandardInput(usd_handle_t * usdP)
427 usd = (usd_handle_t) malloc(sizeof(*usd));
428 memset(usd, 0, sizeof(*usd));
429 usd->handle = (void *)((unsigned long)0);
430 usd->read = usd_FileRead;
431 usd->write = usd_FileWrite;
432 usd->seek = usd_FileSeek;
433 usd->ioctl = usd_FileIoctl;
434 usd->close = usd_FileDummyClose;
435 usd->fullPathName = "STDIN";
443 usd_StandardInput(usd_handle_t * usdP)
445 return usd_FileStandardInput(usdP);
449 usd_FileStandardOutput(usd_handle_t * usdP)
456 usd = (usd_handle_t) malloc(sizeof(*usd));
457 memset(usd, 0, sizeof(*usd));
458 usd->handle = (void *)((unsigned long)1);
459 usd->read = usd_FileRead;
460 usd->write = usd_FileWrite;
461 usd->seek = usd_FileSeek;
462 usd->ioctl = usd_FileIoctl;
463 usd->close = usd_FileDummyClose;
464 usd->fullPathName = "STDOUT";
472 usd_StandardOutput(usd_handle_t * usdP)
474 return usd_FileStandardOutput(usdP);