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>
16 #include <sys/types.h>
19 #if defined(AFS_AIX_ENV)
21 #include <sys/statfs.h>
24 #include <sys/ioccom.h>
26 #if defined(AFS_DUX40_ENV) || defined(AFS_OBSD_ENV) || defined(AFS_NBSD_ENV) || (defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN100_ENV))
27 #include <sys/ioctl.h>
29 #ifndef AFS_DARWIN100_ENV
32 #endif /* AFS_AIX_ENV */
37 #include <afs/debug.h>
41 typedef off64_t osi_lloff_t;
42 #define osi_llseek lseek64
43 #else /* O_LARGEFILE */
44 #ifdef AFS_HAVE_LLSEEK
45 typedef offset_t osi_lloff_t;
46 #define osi_llseek llseek
47 #else /* AFS_HAVE_LLSEEK */
48 typedef off_t osi_lloff_t;
49 #define osi_llseek lseek
50 #endif /* AFS_HAVE_LLSEEK */
51 #endif /* O_LARGEFILE */
54 * This macro should be used inside assertions wherever offset/hyper
55 * conversion occur. A good compiler in a 64 bit environment will
56 * elide the entire statement if the offset type is 64 bits wide.
58 #define osi_hFitsInOff(ahyper, noff) \
59 ((sizeof(noff) == 4) ? hfitsin32(ahyper) : 1)
61 #define osi_h2off(ahyper, noff) \
62 ((sizeof(noff) == 4) \
63 ? ((noff) = (osi_lloff_t)hgetlo(ahyper))\
64 : ((noff) = ((osi_lloff_t)hgethi(ahyper)<<32) | (osi_lloff_t)hgetlo(ahyper)))
66 #define osi_off2h(noff, ahyper) \
67 ((sizeof(noff) == 4) \
68 ? (hset32(ahyper, (int)noff)) \
69 : (hset64(ahyper, (int)((noff>>32)&0xffffffff), ((int)noff&0xffffffff))))
72 /************ End of osi wrappers ***********************************/
74 /* Implementation of user space device I/O for regular POSIX files. */
77 usd_FileRead(usd_handle_t usd, char *buf, afs_uint32 nbytes,
80 int fd = (intptr_t)(usd->handle);
83 got = read(fd, buf, nbytes);
95 usd_FileWrite(usd_handle_t usd, char *buf, afs_uint32 nbytes,
98 int fd = (intptr_t)(usd->handle);
101 sent = write(fd, buf, nbytes);
112 extern osi_lloff_t osi_llseek(int, osi_lloff_t, int);
115 usd_FileSeek(usd_handle_t usd, afs_hyper_t reqOff, int whence,
116 afs_hyper_t * curOffP)
118 int fd = (intptr_t)(usd->handle);
121 if (!osi_hFitsInOff(reqOff, lloff))
124 osi_h2off(reqOff, lloff);
125 lloff = osi_llseek(fd, lloff, whence);
126 if (lloff == (((osi_lloff_t) 0) - 1))
129 osi_off2h(lloff, *curOffP);
135 usd_FileIoctl(usd_handle_t usd, int req, void *arg)
137 int fd = (intptr_t)(usd->handle);
140 #else /* O_LARGEFILE */
142 #endif /* O_LARGEFILE */
144 struct statfs fsinfo; /* AIX stat structure doesn't have st_blksize */
145 #endif /* AFS_AIX_ENV */
151 case USD_IOCTL_GETBLKSIZE:
153 code = fstatfs(fd, &fsinfo);
155 *((long *)arg) = (long)4096;
159 #endif /* AFS_AIX_ENV */
160 case USD_IOCTL_GETTYPE:
161 case USD_IOCTL_GETDEV:
162 case USD_IOCTL_GETSIZE:
164 code = fstat64(fd, &info);
165 #else /* O_LARGEFILE */
166 code = fstat(fd, &info);
167 #endif /* O_LARGEFILE */
174 case USD_IOCTL_GETTYPE:
175 *(int *)arg = info.st_mode & S_IFMT;
177 case USD_IOCTL_GETDEV:
178 if (!(S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)))
179 return ENODEV; /* not a device */
180 *(dev_t *) arg = info.st_rdev;
182 case USD_IOCTL_GETSIZE:
183 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode))
184 return ENOTTY; /* shouldn't be a device */
185 osi_off2h(info.st_size, *(afs_hyper_t *) arg);
187 case USD_IOCTL_GETFULLNAME:
188 *(char **)arg = usd->fullPathName;
191 case USD_IOCTL_SETSIZE:
193 /* We could just use ftruncate in all cases. (This even works on AIX;
194 * I tried it). -blake 931118 */
196 /* However, I'm pretty sure this doesn't work on Ultrix so I am
197 * unsure about OSF/1 and HP/UX. 931118 */
199 size = *(afs_hyper_t *) arg;
200 if (!osi_hFitsInOff(size, off))
202 osi_h2off(size, off);
204 code = ftruncate64(fd, off);
205 #else /* O_LARGEFILE */
206 code = ftruncate(fd, off);
207 #endif /* O_LARGEFILE */
212 case USD_IOCTL_TAPEOPERATION:
214 #ifdef AFS_DARWIN100_ENV
217 usd_tapeop_t *tapeOpp = (usd_tapeop_t *) arg;
218 #if defined(AFS_AIX_ENV)
219 struct stop os_tapeop;
221 if (tapeOpp->tp_op == USDTAPE_WEOF) {
222 os_tapeop.st_op = STWEOF;
223 } else if (tapeOpp->tp_op == USDTAPE_REW) {
224 os_tapeop.st_op = STREW;
225 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
226 os_tapeop.st_op = STFSF;
227 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
228 os_tapeop.st_op = STRSF;
229 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
231 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
234 /* unsupported tape operation */
237 os_tapeop.st_count = tapeOpp->tp_count;
239 code = ioctl(fd, STIOCTOP, &os_tapeop);
241 struct mtop os_tapeop;
243 if (tapeOpp->tp_op == USDTAPE_WEOF) {
244 os_tapeop.mt_op = MTWEOF;
245 } else if (tapeOpp->tp_op == USDTAPE_REW) {
246 os_tapeop.mt_op = MTREW;
247 } else if (tapeOpp->tp_op == USDTAPE_FSF) {
248 os_tapeop.mt_op = MTFSF;
249 } else if (tapeOpp->tp_op == USDTAPE_BSF) {
250 os_tapeop.mt_op = MTBSF;
251 } else if (tapeOpp->tp_op == USDTAPE_PREPARE) {
253 } else if (tapeOpp->tp_op == USDTAPE_SHUTDOWN) {
256 /* unsupported tape operation */
259 os_tapeop.mt_count = tapeOpp->tp_count;
261 code = ioctl(fd, MTIOCTOP, &os_tapeop);
262 #endif /* AFS_AIX_ENV */
272 case USD_IOCTL_GETBLKSIZE:
273 if (S_ISCHR(info.st_mode) || S_ISBLK(info.st_mode)) {
274 *((long *)arg) = (long)4096;
278 *((long *)arg) = (long)fsinfo.f_bsize;
279 #else /* AFS_AIX_ENV */
280 *((long *)arg) = (long)info.st_blksize;
281 #endif /* AFS_AIX_ENV */
291 usd_FileClose(usd_handle_t usd)
293 int fd = (intptr_t)(usd->handle);
297 /* I can't really believe this is necessary. On the one hand the user
298 * space code always uses character devices, which aren't supposed to do
299 * any buffering. On the other, I very much doubt fsyncing a regular file
300 * being salvaged is ever necessary. But the salvager used to do this
301 * before returning, so... */
303 if (usd->openFlags & (O_WRONLY | O_RDWR)) {
305 code = usd_FileIoctl(usd, USD_IOCTL_GETTYPE, &mode);
306 if (code == 0 && S_ISBLK(mode)) {
316 if (usd->fullPathName)
317 free(usd->fullPathName);
324 usd_FileOpen(const char *path, int flags, int mode, usd_handle_t * usdP)
334 oflags = (flags & USD_OPEN_RDWR) ? O_RDWR : O_RDONLY;
336 #ifdef O_SYNC /* AFS_DARWIN_ENV XXX */
337 if (flags & USD_OPEN_SYNC)
341 if (flags & USD_OPEN_CREATE)
345 fd = open64(path, oflags | O_LARGEFILE, mode);
346 #else /* O_LARGEFILE */
347 fd = open(path, oflags, mode);
348 #endif /* O_LARGEFILE */
352 usd = (usd_handle_t) malloc(sizeof(*usd));
353 memset(usd, 0, sizeof(*usd));
354 usd->handle = (void *)(intptr_t)fd;
355 usd->read = usd_FileRead;
356 usd->write = usd_FileWrite;
357 usd->seek = usd_FileSeek;
358 usd->ioctl = usd_FileIoctl;
359 usd->close = usd_FileClose;
360 usd->fullPathName = (char *)malloc(strlen(path) + 1);
361 strcpy(usd->fullPathName, path);
362 usd->openFlags = flags;
365 if (flags & (USD_OPEN_RLOCK | USD_OPEN_WLOCK)) {
368 #else /* O_LARGEFILE */
370 #endif /* O_LARGEFILE */
372 /* make sure both lock bits aren't set */
373 assert(~flags & (USD_OPEN_RLOCK | USD_OPEN_WLOCK));
375 fl.l_type = ((flags & USD_OPEN_RLOCK) ? F_RDLCK : F_WRLCK);
376 fl.l_whence = SEEK_SET;
377 fl.l_start = (osi_lloff_t) 0;
378 fl.l_len = (osi_lloff_t) 0; /* whole file */
380 code = fcntl(fd, F_SETLK64, &fl);
381 #else /* O_LARGEFILE */
382 code = fcntl(fd, F_SETLK, &fl);
383 #endif /* O_LARGEFILE */
387 /* If we're trying to obtain a write lock on a real disk, then the
388 * aggregate must not be attached by the kernel. If so, unlock it
390 * WARNING: The code to check for the above has been removed when this
391 * file was ported from DFS src. It should be put back if
392 * this library is used to access hard disks
396 if (code == 0 && usdP)
404 usd_FileDummyClose(usd_handle_t usd)
411 usd_Open(const char *path, int oflag, int mode, usd_handle_t * usdP)
413 return usd_FileOpen(path, oflag, mode, usdP);
417 usd_FileStandardInput(usd_handle_t * usdP)
424 usd = (usd_handle_t) malloc(sizeof(*usd));
425 memset(usd, 0, sizeof(*usd));
426 usd->handle = (void *)((unsigned long)0);
427 usd->read = usd_FileRead;
428 usd->write = usd_FileWrite;
429 usd->seek = usd_FileSeek;
430 usd->ioctl = usd_FileIoctl;
431 usd->close = usd_FileDummyClose;
432 usd->fullPathName = "STDIN";
440 usd_StandardInput(usd_handle_t * usdP)
442 return usd_FileStandardInput(usdP);
446 usd_FileStandardOutput(usd_handle_t * usdP)
453 usd = (usd_handle_t) malloc(sizeof(*usd));
454 memset(usd, 0, sizeof(*usd));
455 usd->handle = (void *)((unsigned long)1);
456 usd->read = usd_FileRead;
457 usd->write = usd_FileWrite;
458 usd->seek = usd_FileSeek;
459 usd->ioctl = usd_FileIoctl;
460 usd->close = usd_FileDummyClose;
461 usd->fullPathName = "STDOUT";
469 usd_StandardOutput(usd_handle_t * usdP)
471 return usd_FileStandardOutput(usdP);