3 * Copyright 2000, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
12 * User space client specific interface glue
15 #include <afsconfig.h>
16 #include "afs/param.h"
20 #include "afs/sysincludes.h" /* Standard vendor system headers */
23 #include "afsincludes.h" /* Afs-based standard headers */
24 #include "afs_usrops.h"
25 #include "afs/afs_stats.h"
27 #include "afs/cellconfig.h"
29 #include "afs/afsutil.h"
30 #include "afs/afs_bypasscache.h"
31 #include "rx/rx_globals.h"
32 #include "afsd/afsd.h"
38 #ifndef AFS_CACHE_VNODE_PATH
39 #error You must compile UKERNEL code with -DAFS_CACHE_VNODE_PATH
42 #define CACHEINFOFILE "cacheinfo"
43 #define AFSLOGFILE "AFSLog"
44 #define DCACHEFILE "CacheItems"
45 #define VOLINFOFILE "VolumeItems"
46 #define CELLINFOFILE "CellItems"
50 #define MIN(A,B) ((A)<(B)?(A):(B))
53 #define MAX(A,B) ((A)>(B)?(A):(B))
56 extern int cacheDiskType;
58 char afs_LclCellName[64];
60 static struct usr_vnode *afs_FileTable[MAX_OSI_FILES];
61 static int afs_FileFlags[MAX_OSI_FILES];
62 static off_t afs_FileOffsets[MAX_OSI_FILES];
64 #define MAX_CACHE_LOOPS 4
66 static struct usr_vfs afs_RootVfs;
67 static struct usr_vnode *afs_RootVnode = NULL;
68 static struct usr_vnode *afs_CurrentDir = NULL;
70 static char afs_mountDir[1024]; /* AFS mount point */
71 static int afs_mountDirLen; /* strlen of AFS mount point */
73 struct afsconf_dir *afs_cdir; /* config dir */
75 int afs_bufferpages = 100;
77 static usr_key_t afs_global_u_key;
79 static struct usr_proc *afs_global_procp = NULL;
80 static struct usr_ucred *afs_global_ucredp = NULL;
82 struct usr_ucred afs_osi_cred, *afs_osi_credp;
83 usr_mutex_t afs_global_lock;
84 usr_thread_t afs_global_owner;
85 usr_mutex_t rx_global_lock;
86 usr_thread_t rx_global_owner;
88 static usr_mutex_t osi_dummy_lock;
89 static usr_mutex_t osi_waitq_lock;
90 static usr_mutex_t osi_authenticate_lock;
92 afs_lock_t osi_flplock;
93 afs_lock_t osi_fsplock;
96 * Mutex and condition variable used to implement sleep
98 pthread_mutex_t usr_sleep_mutex;
99 pthread_cond_t usr_sleep_cond;
101 int call_syscall(long, long, long, long, long, long);
102 int fork_syscall(long, long, long, long, long, long);
106 * Hash table mapping addresses onto wait structures for
107 * osi_Sleep/osi_Wakeup and osi_Wait/osi_Wakeup
109 typedef struct osi_wait {
113 struct osi_wait *next;
114 struct osi_wait *prev;
116 struct osi_wait *timedNext;
117 struct osi_wait *timedPrev;
121 * Head of the linked list of available waitq structures.
123 static osi_wait_t *osi_waithash_avail;
126 * List of timed waits, NSAPI does not provide a cond_timed
127 * wait, so we need to keep track of the timed waits ourselves and
128 * periodically check for expirations
130 static osi_wait_t *osi_timedwait_head;
131 static osi_wait_t *osi_timedwait_tail;
136 } osi_waithash_table[OSI_WAITHASH_SIZE];
139 * Never call afs_brelse
142 ufs_brelse(struct usr_vnode *vp, struct usr_buf *bp)
149 * I am not sure what to do with these, they assert for now
152 iodone(struct usr_buf *bp)
166 * Every user is a super user
169 afs_osi_suser(afs_ucred_t *credp)
175 afs_suser(afs_ucred_t *credp)
181 * These are no-ops in user space
185 * xflock should never fall through, the only files we know
186 * about are AFS files
196 * ioctl should never fall through, the only files we know
197 * about are AFS files
207 * We do not support the inode related system calls
210 afs_syscall_icreate(long a, long b, long c, long d, long e, long f)
217 afs_syscall_iincdec(int dev, int inode, int inode_p1, int amount)
224 afs_syscall_iopen(int dev, int inode, int usrmod)
231 afs_syscall_ireadwrite(void)
238 * these routines are referenced in the vfsops structure, but
239 * should never get called
270 * uiomove copies data between kernel buffers and uio buffers
273 usr_uiomove(char *kbuf, int n, int rw, struct usr_uio *uio)
280 nio = uio->uio_iovcnt;
290 while (nio > 0 && n > 0) {
291 len = MIN(n, iovp->iov_len);
292 if (rw == UIO_READ) {
293 memcpy(iovp->iov_base, ptr, len);
295 memcpy(ptr, iovp->iov_base, len);
299 uio->uio_resid -= len;
300 uio->uio_offset += len;
301 iovp->iov_base = (char *)(iovp->iov_base) + len;
302 iovp->iov_len -= len;
313 * routines to manage user credentials
316 usr_crcopy(struct usr_ucred *credp)
318 struct usr_ucred *newcredp;
320 newcredp = afs_osi_Alloc(sizeof(struct usr_ucred));
322 newcredp->cr_ref = 1;
329 struct usr_ucred *newcredp;
331 newcredp = afs_osi_Alloc(sizeof(struct usr_ucred));
332 newcredp->cr_ref = 1;
337 usr_crfree(struct usr_ucred *credp)
340 if (credp->cr_ref == 0) {
341 afs_osi_Free((char *)credp, sizeof(struct usr_ucred));
347 usr_crhold(struct usr_ucred *credp)
354 usr_vattr_null(struct usr_vattr *vap)
359 n = sizeof(struct usr_vattr);
367 * Initialize the thread specific data used to simulate the
368 * kernel environment for each thread. The user structure
369 * is stored in the thread specific data.
372 uafs_InitThread(void)
375 struct usr_user *uptr;
378 * initialize the thread specific user structure. Use malloc to
379 * allocate the data block, so pthread_finish can free the buffer
380 * when this thread terminates.
382 uptr = malloc(sizeof(struct usr_user) + sizeof(struct usr_ucred));
383 usr_assert(uptr != NULL);
386 uptr->u_procp = afs_global_procp;
387 uptr->u_cred = (struct usr_ucred *)(uptr + 1);
388 *uptr->u_cred = *afs_global_ucredp;
389 st = usr_setspecific(afs_global_u_key, (void *)uptr);
394 * routine to get the user structure from the thread specific data.
395 * this routine is used to implement the global 'u' structure. Initializes
396 * the thread if needed.
399 get_user_struct(void)
401 struct usr_user *uptr;
404 st = usr_getspecific(afs_global_u_key, &uptr);
408 st = usr_getspecific(afs_global_u_key, &uptr);
410 usr_assert(uptr != NULL);
416 * Hash an address for the waithash table
418 #define WAITHASH(X) \
419 (((long)(X)^((long)(X)>>4)^((long)(X)<<4))&(OSI_WAITHASH_SIZE-1))
425 afs_osi_Sleep(void *x)
429 int glockOwner = ISAFS_GLOCK();
431 usr_mutex_lock(&osi_waitq_lock);
436 if (osi_waithash_avail == NULL) {
437 waitp = afs_osi_Alloc(sizeof(osi_wait_t));
438 usr_cond_init(&waitp->cond);
440 waitp = osi_waithash_avail;
441 osi_waithash_avail = osi_waithash_avail->next;
445 DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
446 osi_waithash_table[index].tail, next, prev);
447 waitp->expiration = 0;
448 waitp->timedNext = NULL;
449 waitp->timedPrev = NULL;
450 while (waitp->flag == 0) {
451 usr_cond_wait(&waitp->cond, &osi_waitq_lock);
453 DLL_DELETE(waitp, osi_waithash_table[index].head,
454 osi_waithash_table[index].tail, next, prev);
455 waitp->next = osi_waithash_avail;
456 osi_waithash_avail = waitp;
457 usr_mutex_unlock(&osi_waitq_lock);
464 afs_osi_SleepSig(void *x)
471 afs_osi_Wakeup(void *x)
477 usr_mutex_lock(&osi_waitq_lock);
478 waitp = osi_waithash_table[index].head;
480 if (waitp->addr == x && waitp->flag == 0) {
482 usr_cond_signal(&waitp->cond);
486 usr_mutex_unlock(&osi_waitq_lock);
491 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
493 return afs_osi_Wait(ams, event, aintok);
497 afs_osi_Wait(afs_int32 msec, struct afs_osi_WaitHandle *handle, int intok)
503 int glockOwner = ISAFS_GLOCK();
505 tv.tv_sec = msec / 1000;
506 tv.tv_nsec = (msec % 1000) * 1000000;
507 if (handle == NULL) {
511 usr_thread_sleep(&tv);
517 usr_mutex_lock(&osi_waitq_lock);
521 index = WAITHASH((caddr_t) handle);
522 if (osi_waithash_avail == NULL) {
523 waitp = afs_osi_Alloc(sizeof(osi_wait_t));
524 usr_cond_init(&waitp->cond);
526 waitp = osi_waithash_avail;
527 osi_waithash_avail = osi_waithash_avail->next;
529 waitp->addr = (caddr_t) handle;
531 DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
532 osi_waithash_table[index].tail, next, prev);
533 tv.tv_sec += time(NULL);
534 waitp->expiration = tv.tv_sec + ((tv.tv_nsec == 0) ? 0 : 1);
535 DLL_INSERT_TAIL(waitp, osi_timedwait_head, osi_timedwait_tail,
536 timedNext, timedPrev);
537 usr_cond_wait(&waitp->cond, &osi_waitq_lock);
543 DLL_DELETE(waitp, osi_waithash_table[index].head,
544 osi_waithash_table[index].tail, next, prev);
545 DLL_DELETE(waitp, osi_timedwait_head, osi_timedwait_tail, timedNext,
547 waitp->next = osi_waithash_avail;
548 osi_waithash_avail = waitp;
549 usr_mutex_unlock(&osi_waitq_lock);
558 afs_osi_CancelWait(struct afs_osi_WaitHandle *handle)
560 afs_osi_Wakeup(handle);
564 * Netscape NSAPI doesn't have a cond_timed_wait, so we need
565 * to explicitly signal cond_timed_waits when their timers expire
568 afs_osi_CheckTimedWaits(void)
573 curTime = time(NULL);
574 usr_mutex_lock(&osi_waitq_lock);
575 waitp = osi_timedwait_head;
576 while (waitp != NULL) {
577 usr_assert(waitp->expiration != 0);
578 if (waitp->expiration <= curTime) {
580 usr_cond_signal(&waitp->cond);
582 waitp = waitp->timedNext;
584 usr_mutex_unlock(&osi_waitq_lock);
589 * 'dummy' vnode, for non-AFS files. We don't actually need most vnode
590 * information for non-AFS files, so point all of them towards this vnode
593 static struct usr_vnode dummy_vnode = {
604 * Allocate a slot in the file table if there is not one there already,
605 * copy in the file name and kludge up the vnode and inode structures
608 lookupname(char *fnamep, int segflg, int followlink,
609 struct usr_vnode **compvpp)
614 * Assume relative pathnames refer to files in AFS
616 if (*fnamep != '/' || uafs_afsPathName(fnamep) != NULL) {
618 code = uafs_LookupName(fnamep, afs_CurrentDir, compvpp, 0, 0);
623 /* For non-afs files, nobody really looks at the meaningful values in the
624 * returned vnode, so we can return a 'fake' one. The vnode can be held,
625 * released, etc. and some callers check for a NULL vnode anyway, so we
626 * to return something. */
628 usr_mutex_lock(&osi_dummy_lock);
629 VN_HOLD(&dummy_vnode);
630 usr_mutex_unlock(&osi_dummy_lock);
632 *compvpp = &dummy_vnode;
638 * open a file given its i-node number
641 osi_UFSOpen(afs_dcache_id_t *ino)
650 fp = afs_osi_Alloc(sizeof(struct osi_file));
651 usr_assert(fp != NULL);
653 usr_assert(ino->ufs);
655 fp->fd = open(ino->ufs, O_RDWR | O_CREAT, 0);
657 get_user_struct()->u_error = errno;
658 afs_osi_Free((char *)fp, sizeof(struct osi_file));
662 rc = fstat(fp->fd, &st);
664 get_user_struct()->u_error = errno;
665 afs_osi_Free((void *)fp, sizeof(struct osi_file));
669 fp->size = st.st_size;
671 fp->vnode = (struct usr_vnode *)fp;
678 osi_UFSClose(struct osi_file *fp)
687 get_user_struct()->u_error = errno;
688 afs_osi_Free((void *)fp, sizeof(struct osi_file));
692 afs_osi_Free((void *)fp, sizeof(struct osi_file));
698 osi_UFSTruncate(struct osi_file *fp, afs_int32 len)
705 rc = ftruncate(fp->fd, len);
707 get_user_struct()->u_error = errno;
717 afs_osi_Read(struct osi_file *fp, int offset, void *buf, afs_int32 len)
726 rc = lseek(fp->fd, offset, SEEK_SET);
728 rc = lseek(fp->fd, fp->offset, SEEK_SET);
731 get_user_struct()->u_error = errno;
736 ret = read(fp->fd, buf, len);
738 get_user_struct()->u_error = errno;
743 rc = fstat(fp->fd, &st);
745 get_user_struct()->u_error = errno;
749 fp->size = st.st_size;
755 afs_osi_Write(struct osi_file *fp, afs_int32 offset, void *buf, afs_int32 len)
764 rc = lseek(fp->fd, offset, SEEK_SET);
766 rc = lseek(fp->fd, fp->offset, SEEK_SET);
769 get_user_struct()->u_error = errno;
774 ret = write(fp->fd, buf, len);
776 get_user_struct()->u_error = errno;
781 rc = fstat(fp->fd, &st);
783 get_user_struct()->u_error = errno;
787 fp->size = st.st_size;
793 afs_osi_Stat(struct osi_file *fp, struct osi_stat *stp)
799 rc = fstat(fp->fd, &st);
801 get_user_struct()->u_error = errno;
805 stp->size = st.st_size;
806 stp->mtime = st.st_mtime;
807 stp->atime = st.st_atime;
816 afs_osi_VOP_RDWR(struct usr_vnode *vnodeP, struct usr_uio *uioP, int rw,
817 int flags, struct usr_ucred *credP)
820 struct osi_file *fp = (struct osi_file *)vnodeP;
823 * We don't support readv/writev.
825 usr_assert(uioP->uio_iovcnt == 1);
826 usr_assert(uioP->uio_resid == uioP->uio_iov[0].iov_len);
828 if (rw == UIO_WRITE) {
829 usr_assert(uioP->uio_fmode == FWRITE);
830 rc = afs_osi_Write(fp, uioP->uio_offset, uioP->uio_iov[0].iov_base,
831 uioP->uio_iov[0].iov_len);
833 usr_assert(uioP->uio_fmode == FREAD);
834 rc = afs_osi_Read(fp, uioP->uio_offset, uioP->uio_iov[0].iov_base,
835 uioP->uio_iov[0].iov_len);
838 return get_user_struct()->u_error;
841 uioP->uio_resid -= rc;
842 uioP->uio_offset += rc;
843 uioP->uio_iov[0].iov_base = (char *)(uioP->uio_iov[0].iov_base) + rc;
844 uioP->uio_iov[0].iov_len -= rc;
849 afs_osi_Alloc(size_t size)
855 afs_osi_Free(void *ptr, size_t size)
861 afs_osi_FreeStr(char *ptr)
867 osi_AllocLargeSpace(size_t size)
869 AFS_STATCNT(osi_AllocLargeSpace);
870 return afs_osi_Alloc(size);
874 osi_FreeLargeSpace(void *ptr)
876 AFS_STATCNT(osi_FreeLargeSpace);
877 afs_osi_Free(ptr, 0);
881 osi_AllocSmallSpace(size_t size)
883 AFS_STATCNT(osi_AllocSmallSpace);
884 return afs_osi_Alloc(size);
888 osi_FreeSmallSpace(void *ptr)
890 AFS_STATCNT(osi_FreeSmallSpace);
891 afs_osi_Free(ptr, 0);
897 AFS_STATCNT(shutdown_osi);
902 shutdown_osinet(void)
904 AFS_STATCNT(shutdown_osinet);
909 shutdown_osifile(void)
911 AFS_STATCNT(shutdown_osifile);
916 afs_nfsclient_init(void)
921 shutdown_nfsclnt(void)
927 afs_osi_Invisible(void)
933 afs_osi_Visible(void)
939 osi_Active(struct vcache *avc)
941 AFS_STATCNT(osi_Active);
948 afs_osi_MapStrategy(int (*aproc) (struct usr_buf *), struct usr_buf *bp)
950 afs_int32 returnCode;
951 returnCode = (*aproc) (bp);
956 osi_FlushPages(struct vcache *avc, afs_ucred_t *credp)
958 ObtainSharedLock(&avc->lock, 555);
959 if ((hcmp((avc->f.m.DataVersion), (avc->mapDV)) <= 0)
960 || ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
961 ReleaseSharedLock(&avc->lock);
964 UpgradeSToWLock(&avc->lock, 565);
965 hset(avc->mapDV, avc->f.m.DataVersion);
966 ReleaseWriteLock(&avc->lock);
971 osi_FlushText_really(struct vcache *vp)
973 if (hcmp(vp->f.m.DataVersion, vp->flushDV) > 0) {
974 hset(vp->flushDV, vp->f.m.DataVersion);
980 osi_SyncVM(struct vcache *avc)
986 osi_ReleaseVM(struct vcache *avc, int len, struct usr_ucred *credp)
998 * Use the thread specific data to implement the user structure
1000 usr_keycreate(&afs_global_u_key, free);
1003 * Initialize the global ucred structure
1005 afs_global_ucredp = (struct usr_ucred *)
1006 afs_osi_Alloc(sizeof(struct usr_ucred));
1007 usr_assert(afs_global_ucredp != NULL);
1008 afs_global_ucredp->cr_ref = 1;
1009 afs_set_cr_uid(afs_global_ucredp, geteuid());
1010 afs_set_cr_gid(afs_global_ucredp, getegid());
1011 afs_set_cr_ruid(afs_global_ucredp, getuid());
1012 afs_set_cr_rgid(afs_global_ucredp, getgid());
1013 afs_global_ucredp->cr_suid = afs_cr_ruid(afs_global_ucredp);
1014 afs_global_ucredp->cr_sgid = afs_cr_rgid(afs_global_ucredp);
1015 st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
1016 usr_assert(st >= 0);
1017 afs_global_ucredp->cr_ngroups = (unsigned long)st;
1018 for (i = st; i < NGROUPS; i++) {
1019 afs_global_ucredp->cr_groups[i] = NOGROUP;
1023 * Initialize the global process structure
1025 afs_global_procp = (struct usr_proc *)
1026 afs_osi_Alloc(sizeof(struct usr_proc));
1027 usr_assert(afs_global_procp != NULL);
1028 afs_global_procp->p_pid = osi_getpid();
1029 afs_global_procp->p_ppid = (pid_t) 1;
1030 afs_global_procp->p_ucred = afs_global_ucredp;
1033 * Initialize the mutex and condition variable used to implement
1036 pthread_mutex_init(&usr_sleep_mutex, NULL);
1037 pthread_cond_init(&usr_sleep_cond, NULL);
1040 * Initialize the hash table used for sleep/wakeup
1042 for (i = 0; i < OSI_WAITHASH_SIZE; i++) {
1043 DLL_INIT_LIST(osi_waithash_table[i].head, osi_waithash_table[i].tail);
1045 DLL_INIT_LIST(osi_timedwait_head, osi_timedwait_tail);
1046 osi_waithash_avail = NULL;
1049 * Initialize the AFS file table
1051 for (i = 0; i < MAX_OSI_FILES; i++) {
1052 afs_FileTable[i] = NULL;
1056 * Initialize the global locks
1058 usr_mutex_init(&afs_global_lock);
1059 usr_mutex_init(&rx_global_lock);
1060 usr_mutex_init(&osi_dummy_lock);
1061 usr_mutex_init(&osi_waitq_lock);
1062 usr_mutex_init(&osi_authenticate_lock);
1065 * Initialize the AFS OSI credentials
1067 afs_osi_cred = *afs_global_ucredp;
1068 afs_osi_credp = &afs_osi_cred;
1070 init_et_to_sys_error();
1074 * Set the UDP port number RX uses for UDP datagrams
1077 uafs_SetRxPort(int port)
1079 usr_assert(usr_rx_port == 0);
1084 * uafs_Init is for backwards compatibility only! Do not use it; use
1085 * uafs_Setup, uafs_ParseArgs, and uafs_Run instead.
1088 uafs_Init(char *rn, char *mountDirParam, char *confDirParam,
1089 char *cacheBaseDirParam, int cacheBlocksParam, int cacheFilesParam,
1090 int cacheStatEntriesParam, int dCacheSizeParam, int vCacheSizeParam,
1091 int chunkSizeParam, int closeSynchParam, int debugParam,
1092 int nDaemonsParam, int cacheFlagsParam, char *logFile)
1102 code = uafs_Setup(mountDirParam);
1103 usr_assert(code == 0);
1106 if (mountDirParam) {
1107 argv[argc++] = "-mountdir";
1108 argv[argc++] = mountDirParam;
1111 argv[argc++] = "-confdir";
1112 argv[argc++] = confDirParam;
1114 if (cacheBaseDirParam) {
1115 argv[argc++] = "-cachedir";
1116 argv[argc++] = cacheBaseDirParam;
1118 if (cacheBlocksParam) {
1119 snprintf(buf, sizeof(buf), "%d", cacheBlocksParam);
1121 argv[argc++] = "-blocks";
1122 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1124 if (cacheFilesParam) {
1125 snprintf(buf, sizeof(buf), "%d", cacheFilesParam);
1127 argv[argc++] = "-files";
1128 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1130 if (cacheStatEntriesParam) {
1131 snprintf(buf, sizeof(buf), "%d", cacheStatEntriesParam);
1133 argv[argc++] = "-stat";
1134 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1136 if (dCacheSizeParam) {
1137 snprintf(buf, sizeof(buf), "%d", dCacheSizeParam);
1139 argv[argc++] = "-dcache";
1140 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1142 if (vCacheSizeParam) {
1143 snprintf(buf, sizeof(buf), "%d", vCacheSizeParam);
1145 argv[argc++] = "-volumes";
1146 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1148 if (chunkSizeParam) {
1149 snprintf(buf, sizeof(buf), "%d", chunkSizeParam);
1151 argv[argc++] = "-chunksize";
1152 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1154 if (closeSynchParam) {
1155 argv[argc++] = "-waitclose";
1158 argv[argc++] = "-debug";
1160 if (nDaemonsParam) {
1161 snprintf(buf, sizeof(buf), "%d", nDaemonsParam);
1163 argv[argc++] = "-daemons";
1164 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1166 if (cacheFlagsParam) {
1167 if (cacheFlagsParam & AFSCALL_INIT_MEMCACHE) {
1168 argv[argc++] = "-memcache";
1172 argv[argc++] = "-logfile";
1173 argv[argc++] = logFile;
1178 code = uafs_ParseArgs(argc, argv);
1179 usr_assert(code == 0);
1181 for (i = 0; i < freeargc; i++) {
1186 usr_assert(code == 0);
1190 * Calculate the cacheMountDir used for a specified dir.
1192 * @param[in] dir Desired mount dir
1193 * @param[out] mountdir On success, contains the literal string that should
1194 * be used as the cache mount dir.
1195 * @param[in] size The number of bytes allocated in mountdir
1197 * @post On success, mountdir begins with a slash, and does not contain two
1198 * slashes adjacent to each other
1200 * @return operation status
1202 * @retval ENAMETOOLONG the specified dir is too long to fix in the given
1204 * @retval EINVAL the specified dir does not actually specify any meaningful
1208 calcMountDir(const char *dir, char *mountdir, size_t size)
1215 if (dir && strlen(dir) > size-1) {
1216 return ENAMETOOLONG;
1220 * Initialize the AFS mount point, default is '/afs'.
1221 * Strip duplicate/trailing slashes from mount point string.
1222 * afs_mountDirLen is set to strlen(afs_mountDir).
1227 sprintf(buf, "%s", dir);
1231 for (lastchar = '/', p = &buf[0]; *p != '\0'; p++) {
1232 if (lastchar != '/' || *p != '/') {
1233 mountdir[len++] = lastchar = *p;
1236 if (lastchar == '/' && len > 1)
1238 mountdir[len] = '\0';
1251 * Mount the AFS filesystem
1254 rc = afs_mount(&afs_RootVfs, NULL, NULL);
1255 usr_assert(rc == 0);
1256 rc = afs_root(&afs_RootVfs, &afs_RootVnode);
1257 usr_assert(rc == 0);
1261 * initialize the current directory to the AFS root
1263 afs_CurrentDir = afs_RootVnode;
1264 VN_HOLD(afs_CurrentDir);
1270 uafs_setMountDir(const char *dir)
1274 char tmp_mountDir[1024];
1276 rc = calcMountDir(dir, tmp_mountDir, sizeof(tmp_mountDir));
1278 afs_warn("Invalid mount dir specification (error %d): %s\n", rc, dir);
1280 if (strcmp(tmp_mountDir, afs_mountDir) != 0) {
1281 /* mount dir changed */
1282 strcpy(afs_mountDir, tmp_mountDir);
1283 afs_mountDirLen = strlen(afs_mountDir);
1290 uafs_statvfs(struct statvfs *buf)
1296 rc = afs_statvfs(&afs_RootVfs, buf);
1316 if (afs_CurrentDir) {
1317 VN_RELE(afs_CurrentDir);
1319 rc = afs_unmount(&afs_RootVfs);
1320 usr_assert(rc == 0);
1327 * Donate the current thread to the RX server pool.
1330 uafs_RxServerProc(void)
1334 struct rx_call *newcall = NULL;
1336 rxi_MorePackets(2); /* alloc more packets */
1337 threadID = rxi_availProcs++;
1340 sock = OSI_NULLSOCKET;
1341 rxi_ServerProc(threadID, newcall, &sock);
1342 if (sock == OSI_NULLSOCKET) {
1347 rxi_ListenerProc(sock, &threadID, &newcall);
1348 /* assert(threadID != -1); */
1349 /* assert(newcall != NULL); */
1353 struct syscallThreadArgs {
1363 syscallThread(void *argp)
1366 struct usr_ucred *crp;
1367 struct syscallThreadArgs *sysArgsP = (struct syscallThreadArgs *)argp;
1370 * AFS daemons run authenticated
1372 get_user_struct()->u_viceid = getuid();
1373 crp = get_user_struct()->u_cred;
1374 afs_set_cr_uid(crp, getuid());
1375 afs_set_cr_ruid(crp, getuid());
1376 crp->cr_suid = getuid();
1377 crp->cr_groups[0] = getgid();
1378 crp->cr_ngroups = 1;
1379 for (i = 1; i < NGROUPS; i++) {
1380 crp->cr_groups[i] = NOGROUP;
1383 call_syscall(sysArgsP->syscall, sysArgsP->afscall, sysArgsP->param1,
1384 sysArgsP->param2, sysArgsP->param3, sysArgsP->param4);
1386 afs_osi_Free(argp, -1);
1391 fork_syscall(long syscall, long afscall, long param1, long param2,
1392 long param3, long param4)
1395 struct syscallThreadArgs *sysArgsP;
1397 sysArgsP = (struct syscallThreadArgs *)
1398 afs_osi_Alloc(sizeof(struct syscallThreadArgs));
1399 usr_assert(sysArgsP != NULL);
1400 sysArgsP->syscall = syscall;
1401 sysArgsP->afscall = afscall;
1402 sysArgsP->param1 = param1;
1403 sysArgsP->param2 = param2;
1404 sysArgsP->param3 = param3;
1405 sysArgsP->param4 = param4;
1407 usr_thread_create(&tid, syscallThread, sysArgsP);
1408 usr_thread_detach(tid);
1413 call_syscall(long syscall, long afscall, long param1, long param2,
1414 long param3, long param4)
1426 a.syscall = syscall;
1427 a.afscall = afscall;
1433 get_user_struct()->u_error = 0;
1434 get_user_struct()->u_ap = (char *)&a;
1436 code = Afs_syscall();
1441 uafs_Setup(const char *mount)
1444 static int inited = 0;
1451 rc = calcMountDir(mount, afs_mountDir, sizeof(afs_mountDir));
1455 afs_mountDirLen = strlen(afs_mountDir);
1457 /* initialize global vars and such */
1460 /* initialize cache manager foo */
1467 uafs_ParseArgs(int argc, char **argv)
1469 return afsd_parse(argc, argv);
1481 return afsd_cacheMountDir;
1485 uafs_SetTokens(char *tbuffer, int tlen)
1488 struct afs_ioctl iob;
1493 iob.out = &outbuf[0];
1494 iob.out_size = sizeof(outbuf);
1496 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
1505 uafs_RPCStatsEnableProc(void)
1508 struct afs_ioctl iob;
1511 flag = AFSCALL_RXSTATS_ENABLE;
1512 iob.in = (char *)&flag;
1513 iob.in_size = sizeof(afs_int32);
1516 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1525 uafs_RPCStatsDisableProc(void)
1528 struct afs_ioctl iob;
1531 flag = AFSCALL_RXSTATS_DISABLE;
1532 iob.in = (char *)&flag;
1533 iob.in_size = sizeof(afs_int32);
1536 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1545 uafs_RPCStatsClearProc(void)
1548 struct afs_ioctl iob;
1551 flag = AFSCALL_RXSTATS_CLEAR;
1552 iob.in = (char *)&flag;
1553 iob.in_size = sizeof(afs_int32);
1556 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1565 uafs_RPCStatsEnablePeer(void)
1568 struct afs_ioctl iob;
1571 flag = AFSCALL_RXSTATS_ENABLE;
1572 iob.in = (char *)&flag;
1573 iob.in_size = sizeof(afs_int32);
1576 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1585 uafs_RPCStatsDisablePeer(void)
1588 struct afs_ioctl iob;
1591 flag = AFSCALL_RXSTATS_DISABLE;
1592 iob.in = (char *)&flag;
1593 iob.in_size = sizeof(afs_int32);
1596 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1605 uafs_RPCStatsClearPeer(void)
1608 struct afs_ioctl iob;
1611 flag = AFSCALL_RXSTATS_CLEAR;
1612 iob.in = (char *)&flag;
1613 iob.in_size = sizeof(afs_int32);
1616 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1625 * Lookup the target of a symbolic link
1626 * Call VN_HOLD on the output vnode if successful.
1627 * Returns zero on success, error code on failure.
1628 * If provided, use a path for confirming we are not linked to ourself.
1630 * Note: Caller must hold the AFS global lock.
1633 uafs_LookupLinkPath(struct usr_vnode *vp, struct usr_vnode *parentVp,
1634 char *ppathP, struct usr_vnode **vpp)
1639 struct usr_vnode *linkVp;
1641 struct iovec iov[1];
1645 pathP = afs_osi_Alloc(MAX_OSI_PATH + 1);
1646 usr_assert(pathP != NULL);
1649 * set up the uio buffer
1651 iov[0].iov_base = pathP;
1652 iov[0].iov_len = MAX_OSI_PATH + 1;
1653 uio.uio_iov = &iov[0];
1657 uio.uio_fmode = FREAD;
1658 uio.uio_resid = MAX_OSI_PATH + 1;
1661 * Read the link data
1663 code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
1665 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1668 len = MAX_OSI_PATH + 1 - uio.uio_resid;
1671 /* are we linked to ourname or ./ourname? ELOOP */
1673 if ((strcmp(pathP, ppathP) == 0) ||
1674 ((pathP[0] == '.') &&
1675 (pathP[1] == '/') &&
1676 (strcmp(&(pathP[2]), ppathP) == 0))) {
1682 * Find the target of the symbolic link
1684 code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
1686 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1690 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1696 * Lookup a file or directory given its path.
1697 * Call VN_HOLD on the output vnode if successful.
1698 * Returns zero on success, error code on failure.
1700 * Note: Caller must hold the AFS global lock.
1703 uafs_LookupName(char *path, struct usr_vnode *parentVp,
1704 struct usr_vnode **vpp, int follow, int no_eval_mtpt)
1708 struct usr_vnode *vp;
1709 struct usr_vnode *nextVp;
1710 struct usr_vnode *linkVp;
1711 struct vcache *nextVc;
1714 char *nextPathP = NULL;
1719 * Absolute paths must start with the AFS mount point.
1721 if (path[0] != '/') {
1724 path = uafs_afsPathName(path);
1732 * Loop through the path looking for the new directory
1734 tmpPath = afs_osi_Alloc(strlen(path) + 1);
1735 usr_assert(tmpPath != NULL);
1736 strcpy(tmpPath, path);
1739 while (pathP != NULL && *pathP != '\0') {
1740 usr_assert(*pathP != '/');
1743 * terminate the current component and skip over slashes
1745 nextPathP = afs_strchr(pathP, '/');
1746 if (nextPathP != NULL) {
1747 while (*nextPathP == '/') {
1748 *(nextPathP++) = '\0';
1753 * Don't call afs_lookup on non-directories
1755 if (vp->v_type != VDIR) {
1757 afs_osi_Free(tmpPath, strlen(path) + 1);
1761 if (vp == afs_RootVnode && strcmp(pathP, "..") == 0) {
1763 * The AFS root is its own parent
1765 nextVp = afs_RootVnode;
1768 * We need execute permission to search a directory
1770 code = afs_access(VTOAFS(vp), VEXEC, get_user_struct()->u_cred);
1773 afs_osi_Free(tmpPath, strlen(path) + 1);
1778 * lookup the next component in the path, we can release the
1779 * subdirectory since we hold the global lock
1783 if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
1784 code = afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred, 0);
1787 afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred,
1790 nextVp=AFSTOV(nextVc);
1793 afs_osi_Free(tmpPath, strlen(path) + 1);
1799 * Follow symbolic links for parent directories and
1800 * for leaves when the follow flag is set.
1802 if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
1804 while (nextVp->v_type == VLNK) {
1805 if (++linkCount > MAX_OSI_LINKS) {
1808 afs_osi_Free(tmpPath, strlen(path) + 1);
1811 code = uafs_LookupLinkPath(nextVp, vp, NULL, &linkVp);
1815 afs_osi_Free(tmpPath, strlen(path) + 1);
1829 * Special case, nextPathP is non-null if pathname ends in slash
1831 if (nextPathP != NULL && vp->v_type != VDIR) {
1833 afs_osi_Free(tmpPath, strlen(path) + 1);
1837 afs_osi_Free(tmpPath, strlen(path) + 1);
1843 uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentVp,
1844 struct usr_vnode **vpp)
1846 return uafs_LookupLinkPath(vp, parentVp, NULL, vpp);
1850 * Lookup the parent of a file or directory given its path
1851 * Call VN_HOLD on the output vnode if successful.
1852 * Returns zero on success, error code on failure.
1854 * Note: Caller must hold the AFS global lock.
1857 uafs_LookupParent(char *path, struct usr_vnode **vpp)
1862 struct usr_vnode *parentP;
1867 * Absolute path names must start with the AFS mount point.
1870 pathP = uafs_afsPathName(path);
1871 if (pathP == NULL) {
1877 * Find the length of the parent path
1880 while (len > 0 && path[len - 1] == '/') {
1886 while (len > 0 && path[len - 1] != '/') {
1893 pathP = afs_osi_Alloc(len);
1894 usr_assert(pathP != NULL);
1895 memcpy(pathP, path, len - 1);
1896 pathP[len - 1] = '\0';
1899 * look up the parent
1901 code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
1902 afs_osi_Free(pathP, len);
1906 if (parentP->v_type != VDIR) {
1916 * Return a pointer to the first character in the last component
1920 uafs_LastPath(char *path)
1925 while (len > 0 && path[len - 1] == '/') {
1928 while (len > 0 && path[len - 1] != '/') {
1938 * Set the working directory.
1941 uafs_chdir(char *path)
1945 retval = uafs_chdir_r(path);
1951 uafs_chdir_r(char *path)
1956 code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
1961 if (dirP->v_type != VDIR) {
1966 VN_RELE(afs_CurrentDir);
1967 afs_CurrentDir = dirP;
1972 * Create a directory.
1975 uafs_mkdir(char *path, int mode)
1979 retval = uafs_mkdir_r(path, mode);
1985 uafs_mkdir_r(char *path, int mode)
1989 struct vnode *parentP;
1990 struct vcache *dirP;
1991 struct usr_vattr attrs;
1993 if (uafs_IsRoot(path)) {
1998 * Look up the parent directory.
2000 nameP = uafs_LastPath(path);
2001 if (nameP != NULL) {
2002 code = uafs_LookupParent(path, &parentP);
2008 parentP = afs_CurrentDir;
2014 * Make sure the directory has at least one character
2016 if (*nameP == '\0') {
2023 * Create the directory
2025 usr_vattr_null(&attrs);
2026 attrs.va_type = VREG;
2027 attrs.va_mode = mode;
2028 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2029 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2031 code = afs_mkdir(VTOAFS(parentP), nameP, &attrs, &dirP, get_user_struct()->u_cred);
2037 VN_RELE(AFSTOV(dirP));
2042 * Return 1 if path is the AFS root, otherwise return 0
2045 uafs_IsRoot(char *path)
2047 while (*path == '/' && *(path + 1) == '/') {
2050 if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2053 path += afs_mountDirLen;
2054 while (*path == '/') {
2057 if (*path != '\0') {
2065 * Note: file name may not end in a slash.
2068 uafs_open(char *path, int flags, int mode)
2072 retval = uafs_open_r(path, flags, mode);
2078 uafs_open_r(char *path, int flags, int mode)
2084 struct usr_vnode *fileP;
2085 struct usr_vnode *dirP;
2086 struct usr_vattr attrs;
2091 if (uafs_IsRoot(path)) {
2092 fileP = afs_RootVnode;
2096 * Look up the parent directory.
2098 nameP = uafs_LastPath(path);
2099 if (nameP != NULL) {
2100 code = uafs_LookupParent(path, &dirP);
2106 dirP = afs_CurrentDir;
2112 * Make sure the filename has at least one character
2114 if (*nameP == '\0') {
2121 * Get the VNODE for this file
2123 if (flags & O_CREAT) {
2124 usr_vattr_null(&attrs);
2125 attrs.va_type = VREG;
2126 attrs.va_mode = mode;
2127 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2128 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2129 if (flags & O_TRUNC) {
2135 afs_create(VTOAFS(dirP), nameP, &attrs,
2136 (flags & O_EXCL) ? usr_EXCL : usr_NONEXCL, mode,
2137 &vc, get_user_struct()->u_cred);
2146 code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2154 * Check whether we have access to this file
2157 if (flags & (O_RDONLY | O_RDWR)) {
2160 if (flags & (O_WRONLY | O_RDWR)) {
2164 fileMode = VREAD; /* since O_RDONLY is 0 */
2165 code = afs_access(VTOAFS(fileP), fileMode, get_user_struct()->u_cred);
2173 * Get the file attributes, all we need is the size
2175 code = afs_getattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2185 * Setup the open flags
2188 if (flags & O_TRUNC) {
2189 openFlags |= FTRUNC;
2191 if (flags & O_APPEND) {
2192 openFlags |= FAPPEND;
2194 if (flags & O_SYNC) {
2197 if (flags & O_SYNC) {
2200 if (flags & (O_RDONLY | O_RDWR)) {
2203 if (flags & (O_WRONLY | O_RDWR)) {
2204 openFlags |= FWRITE;
2206 if ((openFlags & (FREAD | FWRITE)) == 0) {
2207 /* O_RDONLY is 0, so ... */
2212 * Truncate if necessary
2214 if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2215 usr_vattr_null(&attrs);
2216 attrs.va_mask = ATTR_SIZE;
2218 code = afs_setattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2230 code = afs_open(&vc, openFlags, get_user_struct()->u_cred);
2238 * Put the vnode pointer into the file table
2240 for (fd = 0; fd < MAX_OSI_FILES; fd++) {
2241 if (afs_FileTable[fd] == NULL) {
2242 afs_FileTable[fd] = fileP;
2243 afs_FileFlags[fd] = openFlags;
2244 if (flags & O_APPEND) {
2245 afs_FileOffsets[fd] = attrs.va_size;
2247 afs_FileOffsets[fd] = 0;
2252 if (fd == MAX_OSI_FILES) {
2265 uafs_creat(char *path, int mode)
2268 rc = uafs_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2273 uafs_creat_r(char *path, int mode)
2276 rc = uafs_open_r(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2284 uafs_write(int fd, char *buf, int len)
2288 retval = uafs_pwrite_r(fd, buf, len, afs_FileOffsets[fd]);
2294 uafs_pwrite(int fd, char *buf, int len, off_t offset)
2298 retval = uafs_pwrite_r(fd, buf, len, offset);
2304 uafs_pwrite_r(int fd, char *buf, int len, off_t offset)
2308 struct iovec iov[1];
2309 struct usr_vnode *fileP;
2312 * Make sure this is an open file
2314 fileP = afs_FileTable[fd];
2315 if (fileP == NULL) {
2321 * set up the uio buffer
2323 iov[0].iov_base = buf;
2324 iov[0].iov_len = len;
2325 uio.uio_iov = &iov[0];
2327 uio.uio_offset = offset;
2329 uio.uio_fmode = FWRITE;
2330 uio.uio_resid = len;
2336 code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], get_user_struct()->u_cred, 0);
2342 afs_FileOffsets[fd] = uio.uio_offset;
2343 return (len - uio.uio_resid);
2350 uafs_read(int fd, char *buf, int len)
2354 retval = uafs_pread_r(fd, buf, len, afs_FileOffsets[fd]);
2360 uafs_pread_nocache(int fd, char *buf, int len, off_t offset)
2364 retval = uafs_pread_nocache_r(fd, buf, len, offset);
2370 uafs_pread_nocache_r(int fd, char *buf, int len, off_t offset)
2373 struct iovec iov[1];
2374 struct usr_vnode *fileP;
2375 struct nocache_read_request *bparms;
2379 * Make sure this is an open file
2381 fileP = afs_FileTable[fd];
2382 if (fileP == NULL) {
2387 /* these get freed in PrefetchNoCache, so... */
2388 bparms = afs_osi_Alloc(sizeof(struct nocache_read_request));
2390 code = afs_CreateReq(&bparms->areq, get_user_struct()->u_cred);
2392 afs_DestroyReq(bparms->areq);
2393 afs_osi_Free(bparms, sizeof(struct nocache_read_request));
2398 bparms->auio = &uio;
2399 bparms->offset = offset;
2400 bparms->length = len;
2403 * set up the uio buffer
2405 iov[0].iov_base = buf;
2406 iov[0].iov_len = len;
2407 uio.uio_iov = &iov[0];
2409 uio.uio_offset = offset;
2411 uio.uio_fmode = FREAD;
2412 uio.uio_resid = len;
2417 code = afs_PrefetchNoCache(VTOAFS(fileP), get_user_struct()->u_cred,
2425 afs_FileOffsets[fd] = uio.uio_offset;
2426 return (len - uio.uio_resid);
2430 uafs_pread(int fd, char *buf, int len, off_t offset)
2434 retval = uafs_pread_r(fd, buf, len, offset);
2440 uafs_pread_r(int fd, char *buf, int len, off_t offset)
2444 struct iovec iov[1];
2445 struct usr_vnode *fileP;
2448 * Make sure this is an open file
2450 fileP = afs_FileTable[fd];
2451 if (fileP == NULL) {
2457 * set up the uio buffer
2459 iov[0].iov_base = buf;
2460 iov[0].iov_len = len;
2461 uio.uio_iov = &iov[0];
2463 uio.uio_offset = offset;
2465 uio.uio_fmode = FREAD;
2466 uio.uio_resid = len;
2471 code = afs_read(VTOAFS(fileP), &uio, get_user_struct()->u_cred, 0);
2477 afs_FileOffsets[fd] = uio.uio_offset;
2478 return (len - uio.uio_resid);
2482 * Copy the attributes of a file into a stat structure.
2484 * NOTE: Caller must hold the global AFS lock.
2487 uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2490 struct usr_vattr attrs;
2495 * Get the attributes
2497 code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2503 * Copy the attributes, zero fields that aren't set
2505 memset((void *)stats, 0, sizeof(struct stat));
2507 stats->st_ino = attrs.va_nodeid;
2508 stats->st_mode = attrs.va_mode;
2509 stats->st_nlink = attrs.va_nlink;
2510 stats->st_uid = attrs.va_uid;
2511 stats->st_gid = attrs.va_gid;
2512 stats->st_rdev = attrs.va_rdev;
2513 stats->st_size = attrs.va_size;
2514 stats->st_atime = attrs.va_atime.tv_sec;
2515 stats->st_mtime = attrs.va_mtime.tv_sec;
2516 stats->st_ctime = attrs.va_ctime.tv_sec;
2517 /* preserve dv if possible */
2518 #if defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
2519 stats->st_atimespec.tv_nsec = attrs.va_atime.tv_usec * 1000;
2520 stats->st_mtimespec.tv_nsec = attrs.va_mtime.tv_usec * 1000;
2521 stats->st_ctimespec.tv_nsec = attrs.va_ctime.tv_usec * 1000;
2522 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
2523 stats->st_atimensec = attrs.va_atime.tv_usec * 1000;
2524 stats->st_mtimensec = attrs.va_mtime.tv_usec * 1000;
2525 stats->st_ctimensec = attrs.va_ctime.tv_usec * 1000;
2527 stats->st_blksize = attrs.va_blocksize;
2528 stats->st_blocks = attrs.va_blocks;
2534 * Get the attributes of a file, do follow links
2537 uafs_stat(char *path, struct stat *buf)
2541 retval = uafs_stat_r(path, buf);
2547 uafs_stat_r(char *path, struct stat *buf)
2552 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2557 code = uafs_GetAttr(vp, buf);
2567 * Get the attributes of a file, don't follow links
2570 uafs_lstat(char *path, struct stat *buf)
2574 retval = uafs_lstat_r(path, buf);
2580 uafs_lstat_r(char *path, struct stat *buf)
2585 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
2590 code = uafs_GetAttr(vp, buf);
2600 * Get the attributes of an open file
2603 uafs_fstat(int fd, struct stat *buf)
2607 retval = uafs_fstat_r(fd, buf);
2613 uafs_fstat_r(int fd, struct stat *buf)
2618 vp = afs_FileTable[fd];
2623 code = uafs_GetAttr(vp, buf);
2632 * change the permissions on a file
2635 uafs_chmod(char *path, int mode)
2639 retval = uafs_chmod_r(path, mode);
2645 uafs_chmod_r(char *path, int mode)
2649 struct usr_vattr attrs;
2651 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2656 usr_vattr_null(&attrs);
2657 attrs.va_mask = ATTR_MODE;
2658 attrs.va_mode = mode;
2659 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2669 * change the permissions on an open file
2672 uafs_fchmod(int fd, int mode)
2676 retval = uafs_fchmod_r(fd, mode);
2682 uafs_fchmod_r(int fd, int mode)
2686 struct usr_vattr attrs;
2688 vp = afs_FileTable[fd];
2693 usr_vattr_null(&attrs);
2694 attrs.va_mask = ATTR_MODE;
2695 attrs.va_mode = mode;
2696 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2708 uafs_truncate(char *path, int length)
2712 retval = uafs_truncate_r(path, length);
2718 uafs_truncate_r(char *path, int length)
2722 struct usr_vattr attrs;
2724 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2729 usr_vattr_null(&attrs);
2730 attrs.va_mask = ATTR_SIZE;
2731 attrs.va_size = length;
2732 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2742 * truncate an open file
2745 uafs_ftruncate(int fd, int length)
2749 retval = uafs_ftruncate_r(fd, length);
2755 uafs_ftruncate_r(int fd, int length)
2759 struct usr_vattr attrs;
2761 vp = afs_FileTable[fd];
2766 usr_vattr_null(&attrs);
2767 attrs.va_mask = ATTR_SIZE;
2768 attrs.va_size = length;
2769 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2778 * set the read/write file pointer of an open file
2781 uafs_lseek(int fd, int offset, int whence)
2785 retval = uafs_lseek_r(fd, offset, whence);
2791 uafs_lseek_r(int fd, int offset, int whence)
2795 struct usr_vattr attrs;
2796 struct usr_vnode *vp;
2798 vp = afs_FileTable[fd];
2805 newpos = afs_FileOffsets[fd] + offset;
2811 code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2816 newpos = attrs.va_size + offset;
2826 afs_FileOffsets[fd] = newpos;
2838 retval = uafs_fsync_r(fd);
2844 uafs_fsync_r(int fd)
2847 struct usr_vnode *fileP;
2850 fileP = afs_FileTable[fd];
2851 if (fileP == NULL) {
2856 code = afs_fsync(VTOAFS(fileP), get_user_struct()->u_cred);
2873 retval = uafs_close_r(fd);
2879 uafs_close_r(int fd)
2882 struct usr_vnode *fileP;
2884 fileP = afs_FileTable[fd];
2885 if (fileP == NULL) {
2889 afs_FileTable[fd] = NULL;
2891 code = afs_close(VTOAFS(fileP), afs_FileFlags[fd], get_user_struct()->u_cred);
2902 * Create a hard link from the source to the target
2903 * Note: file names may not end in a slash.
2906 uafs_link(char *existing, char *new)
2910 retval = uafs_link_r(existing, new);
2916 uafs_link_r(char *existing, char *new)
2919 struct usr_vnode *existP;
2920 struct usr_vnode *dirP;
2923 if (uafs_IsRoot(new)) {
2928 * Look up the existing node.
2930 code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
2937 * Look up the parent directory.
2939 nameP = uafs_LastPath(new);
2940 if (nameP != NULL) {
2941 code = uafs_LookupParent(new, &dirP);
2948 dirP = afs_CurrentDir;
2954 * Make sure the filename has at least one character
2956 if (*nameP == '\0') {
2966 code = afs_link(VTOAFS(existP), VTOAFS(dirP), nameP, get_user_struct()->u_cred);
2977 * Create a symbolic link from the source to the target
2978 * Note: file names may not end in a slash.
2981 uafs_symlink(char *target, char *source)
2985 retval = uafs_symlink_r(target, source);
2991 uafs_symlink_r(char *target, char *source)
2994 struct usr_vnode *dirP;
2995 struct usr_vattr attrs;
2998 if (uafs_IsRoot(source)) {
3003 * Look up the parent directory.
3005 nameP = uafs_LastPath(source);
3006 if (nameP != NULL) {
3007 code = uafs_LookupParent(source, &dirP);
3013 dirP = afs_CurrentDir;
3019 * Make sure the filename has at least one character
3021 if (*nameP == '\0') {
3030 usr_vattr_null(&attrs);
3031 attrs.va_type = VLNK;
3032 attrs.va_mode = 0777;
3033 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
3034 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
3035 code = afs_symlink(VTOAFS(dirP), nameP, &attrs, target, NULL,
3036 get_user_struct()->u_cred);
3046 * Read a symbolic link into the buffer
3049 uafs_readlink(char *path, char *buf, int len)
3053 retval = uafs_readlink_r(path, buf, len);
3059 uafs_readlink_r(char *path, char *buf, int len)
3062 struct usr_vnode *vp;
3064 struct iovec iov[1];
3066 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3072 if (vp->v_type != VLNK) {
3079 * set up the uio buffer
3081 iov[0].iov_base = buf;
3082 iov[0].iov_len = len;
3083 uio.uio_iov = &iov[0];
3087 uio.uio_fmode = FREAD;
3088 uio.uio_resid = len;
3093 code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3101 * return the number of bytes read
3103 return (len - uio.uio_resid);
3107 * Remove a file (or directory)
3108 * Note: file name may not end in a slash.
3111 uafs_unlink(char *path)
3115 retval = uafs_unlink_r(path);
3121 uafs_unlink_r(char *path)
3124 struct usr_vnode *dirP;
3127 if (uafs_IsRoot(path)) {
3132 * Look up the parent directory.
3134 nameP = uafs_LastPath(path);
3135 if (nameP != NULL) {
3136 code = uafs_LookupParent(path, &dirP);
3142 dirP = afs_CurrentDir;
3148 * Make sure the filename has at least one character
3150 if (*nameP == '\0') {
3159 code = afs_remove(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3170 * Rename a file (or directory)
3173 uafs_rename(char *old, char *new)
3177 retval = uafs_rename_r(old, new);
3183 uafs_rename_r(char *old, char *new)
3188 struct usr_vnode *odirP;
3189 struct usr_vnode *ndirP;
3191 if (uafs_IsRoot(new)) {
3196 * Look up the parent directories.
3198 onameP = uafs_LastPath(old);
3199 if (onameP != NULL) {
3200 code = uafs_LookupParent(old, &odirP);
3206 odirP = afs_CurrentDir;
3210 nnameP = uafs_LastPath(new);
3211 if (nnameP != NULL) {
3212 code = uafs_LookupParent(new, &ndirP);
3218 ndirP = afs_CurrentDir;
3224 * Make sure the filename has at least one character
3226 if (*onameP == '\0' || *nnameP == '\0') {
3236 code = afs_rename(VTOAFS(odirP), onameP, VTOAFS(ndirP), nnameP, get_user_struct()->u_cred);
3248 * Remove a or directory
3249 * Note: file name may not end in a slash.
3252 uafs_rmdir(char *path)
3256 retval = uafs_rmdir_r(path);
3262 uafs_rmdir_r(char *path)
3265 struct usr_vnode *dirP;
3268 if (uafs_IsRoot(path)) {
3273 * Look up the parent directory.
3275 nameP = uafs_LastPath(path);
3276 if (nameP != NULL) {
3277 code = uafs_LookupParent(path, &dirP);
3283 dirP = afs_CurrentDir;
3289 * Make sure the directory name has at least one character
3291 if (*nameP == '\0') {
3298 * Remove the directory
3300 code = afs_rmdir(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3311 * Flush a file from the AFS cache
3314 uafs_FlushFile(char *path)
3317 struct afs_ioctl iob;
3325 call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6), (long)&iob, 0,
3336 uafs_FlushFile_r(char *path)
3340 retval = uafs_FlushFile(path);
3349 uafs_opendir(char *path)
3353 retval = uafs_opendir_r(path);
3359 uafs_opendir_r(char *path)
3362 struct usr_vnode *fileP;
3366 * Open the directory for reading
3368 fd = uafs_open_r(path, O_RDONLY, 0);
3373 fileP = afs_FileTable[fd];
3374 if (fileP == NULL) {
3378 if (fileP->v_type != VDIR) {
3385 * Set up the directory structures
3387 dirp = afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3388 sizeof(struct usr_dirent));
3389 usr_assert(dirp != NULL);
3390 dirp->dd_buf = (char *)(dirp + 1);
3400 * Read directory entries into a file system independent format.
3401 * This routine was developed to support AFS cache consistency testing.
3402 * You should use uafs_readdir instead.
3405 uafs_getdents(int fd, struct min_direct *buf, int len)
3409 retval = uafs_getdents_r(fd, buf, len);
3415 uafs_getdents_r(int fd, struct min_direct *buf, int len)
3419 struct usr_vnode *vp;
3420 struct iovec iov[1];
3423 * Make sure this is an open file
3425 vp = afs_FileTable[fd];
3433 * set up the uio buffer
3435 iov[0].iov_base = (char *)buf;
3436 iov[0].iov_len = len;
3437 uio.uio_iov = &iov[0];
3439 uio.uio_offset = afs_FileOffsets[fd];
3441 uio.uio_fmode = FREAD;
3442 uio.uio_resid = len;
3445 * read the next chunk from the directory
3447 code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3453 afs_FileOffsets[fd] = uio.uio_offset;
3454 return (len - uio.uio_resid);
3458 * read from a directory (names only)
3461 uafs_readdir(usr_DIR * dirp)
3463 struct usr_dirent *retval;
3465 retval = uafs_readdir_r(dirp);
3471 uafs_readdir_r(usr_DIR * dirp)
3476 struct usr_vnode *vp;
3477 struct iovec iov[1];
3478 struct usr_dirent *direntP;
3479 struct min_direct *directP;
3487 * Make sure this is an open file
3489 vp = afs_FileTable[dirp->dd_fd];
3496 * If there are no entries in the stream buffer
3497 * then read another chunk
3499 directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3500 if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3502 * set up the uio buffer
3504 iov[0].iov_base = dirp->dd_buf;
3505 iov[0].iov_len = USR_DIRSIZE;
3506 uio.uio_iov = &iov[0];
3508 uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3510 uio.uio_fmode = FREAD;
3511 uio.uio_resid = USR_DIRSIZE;
3514 * read the next chunk from the directory
3516 code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3521 afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3523 dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3525 directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3529 * Check for end of file
3531 if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3535 len = ((sizeof(struct min_direct) + directP->d_namlen + 4) & (~3));
3536 usr_assert(len <= dirp->dd_size);
3539 * Copy the next entry into the usr_dirent structure and advance
3541 direntP = (struct usr_dirent *)(dirp->dd_buf + USR_DIRSIZE);
3542 direntP->d_ino = directP->d_fileno;
3543 direntP->d_off = direntP->d_reclen;
3545 sizeof(struct usr_dirent) - MAXNAMLEN + directP->d_namlen + 1;
3546 memcpy(&direntP->d_name[0], (void *)(directP + 1), directP->d_namlen);
3547 direntP->d_name[directP->d_namlen] = '\0';
3548 dirp->dd_loc += len;
3549 dirp->dd_size -= len;
3558 uafs_closedir(usr_DIR * dirp)
3562 retval = uafs_closedir_r(dirp);
3568 uafs_closedir_r(usr_DIR * dirp)
3579 afs_osi_Free((char *)dirp,
3580 sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
3581 rc = uafs_close_r(fd);
3586 * Destroy AFS credentials from the kernel cache
3593 usr_mutex_lock(&osi_authenticate_lock);
3594 code = ktc_ForgetAllTokens();
3595 usr_mutex_unlock(&osi_authenticate_lock);
3604 retval = uafs_unlog();
3610 * Strip the AFS mount point from a pathname string. Return
3611 * NULL if the path is a relative pathname or if the path
3612 * doesn't start with the AFS mount point string.
3615 uafs_afsPathName(char *path)
3624 for (i = 1, p = path + 1; *p != '\0'; p++) {
3625 /* Ignore duplicate slashes */
3626 if (*p == '/' && lastchar == '/')
3628 /* Is this a subdirectory of the AFS mount point? */
3629 if (afs_mountDir[i] == '\0' && *p == '/') {
3630 /* strip leading slashes */
3631 while (*(++p) == '/');
3634 /* Reject paths that are not within AFS */
3635 if (*p != afs_mountDir[i])
3640 /* Is this the AFS mount point? */
3641 if (afs_mountDir[i] == '\0') {
3642 usr_assert(*p == '\0');
3649 * uafs_getcellstatus
3650 * get the cell status
3653 uafs_getcellstatus(char *cell, afs_int32 * status)
3656 struct afs_ioctl iob;
3659 iob.in_size = strlen(cell) + 1;
3663 rc = call_syscall(AFSCALL_PIOCTL, /*path */ 0, _VICEIOCTL(35),
3671 *status = (intptr_t)iob.out;
3677 * Get quota of volume associated with path
3680 uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
3683 struct afs_ioctl iob;
3684 VolumeStatus status;
3688 iob.out = (char *)&status;
3689 iob.out_size = sizeof status;
3691 rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
3699 *BlocksInUse = status.BlocksInUse;
3700 *MaxQuota = status.MaxQuota;
3706 * Set quota of volume associated with path
3709 uafs_setvolquota(char *path, afs_int32 MaxQuota)
3712 struct afs_ioctl iob;
3713 VolumeStatus status = { 0 };
3715 iob.in = (char *)&status;
3716 iob.in_size = sizeof status;
3720 status.MaxQuota = MaxQuota;
3721 status.MinQuota = -1;
3723 rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
3735 * uafs_statmountpoint
3736 * Determine whether a dir. is a mount point or not
3737 * return 1 if mount point, 0 if not
3740 uafs_statmountpoint(char *path)
3745 retval = uafs_statmountpoint_r(path);
3751 uafs_statmountpoint_r(char *path)
3758 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
3773 * Get a list of rights for the current user on path.
3776 uafs_access(char *path, int flags)
3793 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3800 code = afs_access(VTOAFS(vp), fileMode, get_user_struct()->u_cred);
3807 return code ? -1 : 0;
3812 * Get a list of rights for the current user on path.
3815 uafs_getRights(char *path)
3822 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3830 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
3831 | PRSFS_LOCK | PRSFS_ADMINISTER;
3833 afs_rights = afs_getRights(VTOAFS(vp), afs_rights, get_user_struct()->u_cred);
3838 #endif /* UKERNEL */