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(void *credp)
175 afs_suser(void *credp)
181 * These are no-ops in user space
185 afs_osi_SetTime(osi_timeval_t * atv)
191 * xflock should never fall through, the only files we know
192 * about are AFS files
202 * ioctl should never fall through, the only files we know
203 * about are AFS files
213 * We do not support the inode related system calls
216 afs_syscall_icreate(long a, long b, long c, long d, long e, long f)
223 afs_syscall_iincdec(int dev, int inode, int inode_p1, int amount)
230 afs_syscall_iopen(int dev, int inode, int usrmod)
237 afs_syscall_ireadwrite(void)
244 * these routines are referenced in the vfsops structure, but
245 * should never get called
276 * uiomove copies data between kernel buffers and uio buffers
279 usr_uiomove(char *kbuf, int n, int rw, struct usr_uio *uio)
286 nio = uio->uio_iovcnt;
296 while (nio > 0 && n > 0) {
297 len = MIN(n, iovp->iov_len);
298 if (rw == UIO_READ) {
299 memcpy(iovp->iov_base, ptr, len);
301 memcpy(ptr, iovp->iov_base, len);
305 uio->uio_resid -= len;
306 uio->uio_offset += len;
307 iovp->iov_base = (char *)(iovp->iov_base) + len;
308 iovp->iov_len -= len;
319 * routines to manage user credentials
322 usr_crcopy(struct usr_ucred *credp)
324 struct usr_ucred *newcredp;
326 newcredp = afs_osi_Alloc(sizeof(struct usr_ucred));
328 newcredp->cr_ref = 1;
335 struct usr_ucred *newcredp;
337 newcredp = afs_osi_Alloc(sizeof(struct usr_ucred));
338 newcredp->cr_ref = 1;
343 usr_crfree(struct usr_ucred *credp)
346 if (credp->cr_ref == 0) {
347 afs_osi_Free((char *)credp, sizeof(struct usr_ucred));
353 usr_crhold(struct usr_ucred *credp)
360 usr_vattr_null(struct usr_vattr *vap)
365 n = sizeof(struct usr_vattr);
373 * Initialize the thread specific data used to simulate the
374 * kernel environment for each thread. The user structure
375 * is stored in the thread specific data.
378 uafs_InitThread(void)
381 struct usr_user *uptr;
384 * initialize the thread specific user structure. Use malloc to
385 * allocate the data block, so pthread_finish can free the buffer
386 * when this thread terminates.
388 uptr = malloc(sizeof(struct usr_user) + sizeof(struct usr_ucred));
389 usr_assert(uptr != NULL);
392 uptr->u_procp = afs_global_procp;
393 uptr->u_cred = (struct usr_ucred *)(uptr + 1);
394 *uptr->u_cred = *afs_global_ucredp;
395 st = usr_setspecific(afs_global_u_key, (void *)uptr);
400 * routine to get the user structure from the thread specific data.
401 * this routine is used to implement the global 'u' structure. Initializes
402 * the thread if needed.
405 get_user_struct(void)
407 struct usr_user *uptr;
410 st = usr_getspecific(afs_global_u_key, &uptr);
414 st = usr_getspecific(afs_global_u_key, &uptr);
416 usr_assert(uptr != NULL);
422 * Hash an address for the waithash table
424 #define WAITHASH(X) \
425 (((long)(X)^((long)(X)>>4)^((long)(X)<<4))&(OSI_WAITHASH_SIZE-1))
431 afs_osi_Sleep(void *x)
435 int glockOwner = ISAFS_GLOCK();
437 usr_mutex_lock(&osi_waitq_lock);
442 if (osi_waithash_avail == NULL) {
443 waitp = afs_osi_Alloc(sizeof(osi_wait_t));
444 usr_cond_init(&waitp->cond);
446 waitp = osi_waithash_avail;
447 osi_waithash_avail = osi_waithash_avail->next;
451 DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
452 osi_waithash_table[index].tail, next, prev);
453 waitp->expiration = 0;
454 waitp->timedNext = NULL;
455 waitp->timedPrev = NULL;
456 while (waitp->flag == 0) {
457 usr_cond_wait(&waitp->cond, &osi_waitq_lock);
459 DLL_DELETE(waitp, osi_waithash_table[index].head,
460 osi_waithash_table[index].tail, next, prev);
461 waitp->next = osi_waithash_avail;
462 osi_waithash_avail = waitp;
463 usr_mutex_unlock(&osi_waitq_lock);
470 afs_osi_SleepSig(void *x)
477 afs_osi_Wakeup(void *x)
483 usr_mutex_lock(&osi_waitq_lock);
484 waitp = osi_waithash_table[index].head;
486 if (waitp->addr == x && waitp->flag == 0) {
488 usr_cond_signal(&waitp->cond);
492 usr_mutex_unlock(&osi_waitq_lock);
497 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
499 return afs_osi_Wait(ams, event, aintok);
503 afs_osi_Wait(afs_int32 msec, struct afs_osi_WaitHandle *handle, int intok)
509 int glockOwner = ISAFS_GLOCK();
511 tv.tv_sec = msec / 1000;
512 tv.tv_nsec = (msec % 1000) * 1000000;
513 if (handle == NULL) {
517 usr_thread_sleep(&tv);
523 usr_mutex_lock(&osi_waitq_lock);
527 index = WAITHASH((caddr_t) handle);
528 if (osi_waithash_avail == NULL) {
529 waitp = afs_osi_Alloc(sizeof(osi_wait_t));
530 usr_cond_init(&waitp->cond);
532 waitp = osi_waithash_avail;
533 osi_waithash_avail = osi_waithash_avail->next;
535 waitp->addr = (caddr_t) handle;
537 DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
538 osi_waithash_table[index].tail, next, prev);
539 tv.tv_sec += time(NULL);
540 waitp->expiration = tv.tv_sec + ((tv.tv_nsec == 0) ? 0 : 1);
541 DLL_INSERT_TAIL(waitp, osi_timedwait_head, osi_timedwait_tail,
542 timedNext, timedPrev);
543 usr_cond_wait(&waitp->cond, &osi_waitq_lock);
549 DLL_DELETE(waitp, osi_waithash_table[index].head,
550 osi_waithash_table[index].tail, next, prev);
551 DLL_DELETE(waitp, osi_timedwait_head, osi_timedwait_tail, timedNext,
553 waitp->next = osi_waithash_avail;
554 osi_waithash_avail = waitp;
555 usr_mutex_unlock(&osi_waitq_lock);
564 afs_osi_CancelWait(struct afs_osi_WaitHandle *handle)
566 afs_osi_Wakeup(handle);
570 * Netscape NSAPI doesn't have a cond_timed_wait, so we need
571 * to explicitly signal cond_timed_waits when their timers expire
574 afs_osi_CheckTimedWaits(void)
579 curTime = time(NULL);
580 usr_mutex_lock(&osi_waitq_lock);
581 waitp = osi_timedwait_head;
582 while (waitp != NULL) {
583 usr_assert(waitp->expiration != 0);
584 if (waitp->expiration <= curTime) {
586 usr_cond_signal(&waitp->cond);
588 waitp = waitp->timedNext;
590 usr_mutex_unlock(&osi_waitq_lock);
595 * 'dummy' vnode, for non-AFS files. We don't actually need most vnode
596 * information for non-AFS files, so point all of them towards this vnode
599 static struct usr_vnode dummy_vnode = {
610 * Allocate a slot in the file table if there is not one there already,
611 * copy in the file name and kludge up the vnode and inode structures
614 lookupname(char *fnamep, int segflg, int followlink,
615 struct usr_vnode **compvpp)
620 * Assume relative pathnames refer to files in AFS
622 if (*fnamep != '/' || uafs_afsPathName(fnamep) != NULL) {
624 code = uafs_LookupName(fnamep, afs_CurrentDir, compvpp, 0, 0);
629 /* For non-afs files, nobody really looks at the meaningful values in the
630 * returned vnode, so we can return a 'fake' one. The vnode can be held,
631 * released, etc. and some callers check for a NULL vnode anyway, so we
632 * to return something. */
634 usr_mutex_lock(&osi_dummy_lock);
635 VN_HOLD(&dummy_vnode);
636 usr_mutex_unlock(&osi_dummy_lock);
638 *compvpp = &dummy_vnode;
644 * open a file given its i-node number
647 osi_UFSOpen(afs_dcache_id_t *ino)
656 fp = afs_osi_Alloc(sizeof(struct osi_file));
657 usr_assert(fp != NULL);
659 usr_assert(ino->ufs);
661 fp->fd = open(ino->ufs, O_RDWR | O_CREAT, 0);
663 get_user_struct()->u_error = errno;
664 afs_osi_Free((char *)fp, sizeof(struct osi_file));
668 rc = fstat(fp->fd, &st);
670 get_user_struct()->u_error = errno;
671 afs_osi_Free((void *)fp, sizeof(struct osi_file));
675 fp->size = st.st_size;
677 fp->vnode = (struct usr_vnode *)fp;
684 osi_UFSClose(struct osi_file *fp)
693 get_user_struct()->u_error = errno;
694 afs_osi_Free((void *)fp, sizeof(struct osi_file));
698 afs_osi_Free((void *)fp, sizeof(struct osi_file));
704 osi_UFSTruncate(struct osi_file *fp, afs_int32 len)
711 rc = ftruncate(fp->fd, len);
713 get_user_struct()->u_error = errno;
723 afs_osi_Read(struct osi_file *fp, int offset, void *buf, afs_int32 len)
732 rc = lseek(fp->fd, offset, SEEK_SET);
734 rc = lseek(fp->fd, fp->offset, SEEK_SET);
737 get_user_struct()->u_error = errno;
742 ret = read(fp->fd, buf, len);
744 get_user_struct()->u_error = errno;
749 rc = fstat(fp->fd, &st);
751 get_user_struct()->u_error = errno;
755 fp->size = st.st_size;
761 afs_osi_Write(struct osi_file *fp, afs_int32 offset, void *buf, afs_int32 len)
770 rc = lseek(fp->fd, offset, SEEK_SET);
772 rc = lseek(fp->fd, fp->offset, SEEK_SET);
775 get_user_struct()->u_error = errno;
780 ret = write(fp->fd, buf, len);
782 get_user_struct()->u_error = errno;
787 rc = fstat(fp->fd, &st);
789 get_user_struct()->u_error = errno;
793 fp->size = st.st_size;
799 afs_osi_Stat(struct osi_file *fp, struct osi_stat *stp)
805 rc = fstat(fp->fd, &st);
807 get_user_struct()->u_error = errno;
811 stp->size = st.st_size;
812 stp->mtime = st.st_mtime;
813 stp->atime = st.st_atime;
822 afs_osi_VOP_RDWR(struct usr_vnode *vnodeP, struct usr_uio *uioP, int rw,
823 int flags, struct usr_ucred *credP)
826 struct osi_file *fp = (struct osi_file *)vnodeP;
829 * We don't support readv/writev.
831 usr_assert(uioP->uio_iovcnt == 1);
832 usr_assert(uioP->uio_resid == uioP->uio_iov[0].iov_len);
834 if (rw == UIO_WRITE) {
835 usr_assert(uioP->uio_fmode == FWRITE);
836 rc = afs_osi_Write(fp, uioP->uio_offset, uioP->uio_iov[0].iov_base,
837 uioP->uio_iov[0].iov_len);
839 usr_assert(uioP->uio_fmode == FREAD);
840 rc = afs_osi_Read(fp, uioP->uio_offset, uioP->uio_iov[0].iov_base,
841 uioP->uio_iov[0].iov_len);
844 return get_user_struct()->u_error;
847 uioP->uio_resid -= rc;
848 uioP->uio_offset += rc;
849 uioP->uio_iov[0].iov_base = (char *)(uioP->uio_iov[0].iov_base) + rc;
850 uioP->uio_iov[0].iov_len -= rc;
855 afs_osi_Alloc(size_t size)
861 afs_osi_Free(void *ptr, size_t size)
867 afs_osi_FreeStr(char *ptr)
873 osi_AllocLargeSpace(size_t size)
875 AFS_STATCNT(osi_AllocLargeSpace);
876 return afs_osi_Alloc(size);
880 osi_FreeLargeSpace(void *ptr)
882 AFS_STATCNT(osi_FreeLargeSpace);
883 afs_osi_Free(ptr, 0);
887 osi_AllocSmallSpace(size_t size)
889 AFS_STATCNT(osi_AllocSmallSpace);
890 return afs_osi_Alloc(size);
894 osi_FreeSmallSpace(void *ptr)
896 AFS_STATCNT(osi_FreeSmallSpace);
897 afs_osi_Free(ptr, 0);
903 AFS_STATCNT(shutdown_osi);
908 shutdown_osinet(void)
910 AFS_STATCNT(shutdown_osinet);
915 shutdown_osifile(void)
917 AFS_STATCNT(shutdown_osifile);
922 afs_nfsclient_init(void)
927 shutdown_nfsclnt(void)
933 afs_osi_Invisible(void)
939 afs_osi_Visible(void)
945 osi_GetTime(struct timeval *tv)
947 gettimeofday(tv, NULL);
952 osi_SetTime(struct timeval *tv)
958 osi_Active(struct vcache *avc)
960 AFS_STATCNT(osi_Active);
967 afs_osi_MapStrategy(int (*aproc) (struct usr_buf *), struct usr_buf *bp)
969 afs_int32 returnCode;
970 returnCode = (*aproc) (bp);
975 osi_FlushPages(struct vcache *avc, afs_ucred_t *credp)
977 ObtainSharedLock(&avc->lock, 555);
978 if ((hcmp((avc->f.m.DataVersion), (avc->mapDV)) <= 0)
979 || ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
980 ReleaseSharedLock(&avc->lock);
983 UpgradeSToWLock(&avc->lock, 565);
984 hset(avc->mapDV, avc->f.m.DataVersion);
985 ReleaseWriteLock(&avc->lock);
990 osi_FlushText_really(struct vcache *vp)
992 if (hcmp(vp->f.m.DataVersion, vp->flushDV) > 0) {
993 hset(vp->flushDV, vp->f.m.DataVersion);
999 osi_SyncVM(struct vcache *avc)
1005 osi_ReleaseVM(struct vcache *avc, int len, struct usr_ucred *credp)
1017 * Use the thread specific data to implement the user structure
1019 usr_keycreate(&afs_global_u_key, free);
1022 * Initialize the global ucred structure
1024 afs_global_ucredp = (struct usr_ucred *)
1025 afs_osi_Alloc(sizeof(struct usr_ucred));
1026 usr_assert(afs_global_ucredp != NULL);
1027 afs_global_ucredp->cr_ref = 1;
1028 afs_set_cr_uid(afs_global_ucredp, geteuid());
1029 afs_set_cr_gid(afs_global_ucredp, getegid());
1030 afs_set_cr_ruid(afs_global_ucredp, getuid());
1031 afs_set_cr_rgid(afs_global_ucredp, getgid());
1032 afs_global_ucredp->cr_suid = afs_cr_ruid(afs_global_ucredp);
1033 afs_global_ucredp->cr_sgid = afs_cr_rgid(afs_global_ucredp);
1034 st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
1035 usr_assert(st >= 0);
1036 afs_global_ucredp->cr_ngroups = (unsigned long)st;
1037 for (i = st; i < NGROUPS; i++) {
1038 afs_global_ucredp->cr_groups[i] = NOGROUP;
1042 * Initialize the global process structure
1044 afs_global_procp = (struct usr_proc *)
1045 afs_osi_Alloc(sizeof(struct usr_proc));
1046 usr_assert(afs_global_procp != NULL);
1047 afs_global_procp->p_pid = osi_getpid();
1048 afs_global_procp->p_ppid = (pid_t) 1;
1049 afs_global_procp->p_ucred = afs_global_ucredp;
1052 * Initialize the mutex and condition variable used to implement
1055 pthread_mutex_init(&usr_sleep_mutex, NULL);
1056 pthread_cond_init(&usr_sleep_cond, NULL);
1059 * Initialize the hash table used for sleep/wakeup
1061 for (i = 0; i < OSI_WAITHASH_SIZE; i++) {
1062 DLL_INIT_LIST(osi_waithash_table[i].head, osi_waithash_table[i].tail);
1064 DLL_INIT_LIST(osi_timedwait_head, osi_timedwait_tail);
1065 osi_waithash_avail = NULL;
1068 * Initialize the AFS file table
1070 for (i = 0; i < MAX_OSI_FILES; i++) {
1071 afs_FileTable[i] = NULL;
1075 * Initialize the global locks
1077 usr_mutex_init(&afs_global_lock);
1078 usr_mutex_init(&rx_global_lock);
1079 usr_mutex_init(&osi_dummy_lock);
1080 usr_mutex_init(&osi_waitq_lock);
1081 usr_mutex_init(&osi_authenticate_lock);
1084 * Initialize the AFS OSI credentials
1086 afs_osi_cred = *afs_global_ucredp;
1087 afs_osi_credp = &afs_osi_cred;
1089 init_et_to_sys_error();
1093 * Set the UDP port number RX uses for UDP datagrams
1096 uafs_SetRxPort(int port)
1098 usr_assert(usr_rx_port == 0);
1103 * uafs_Init is for backwards compatibility only! Do not use it; use
1104 * uafs_Setup, uafs_ParseArgs, and uafs_Run instead.
1107 uafs_Init(char *rn, char *mountDirParam, char *confDirParam,
1108 char *cacheBaseDirParam, int cacheBlocksParam, int cacheFilesParam,
1109 int cacheStatEntriesParam, int dCacheSizeParam, int vCacheSizeParam,
1110 int chunkSizeParam, int closeSynchParam, int debugParam,
1111 int nDaemonsParam, int cacheFlagsParam, char *logFile)
1121 code = uafs_Setup(mountDirParam);
1122 usr_assert(code == 0);
1125 if (mountDirParam) {
1126 argv[argc++] = "-mountdir";
1127 argv[argc++] = mountDirParam;
1130 argv[argc++] = "-confdir";
1131 argv[argc++] = confDirParam;
1133 if (cacheBaseDirParam) {
1134 argv[argc++] = "-cachedir";
1135 argv[argc++] = cacheBaseDirParam;
1137 if (cacheBlocksParam) {
1138 snprintf(buf, sizeof(buf), "%d", cacheBlocksParam);
1140 argv[argc++] = "-blocks";
1141 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1143 if (cacheFilesParam) {
1144 snprintf(buf, sizeof(buf), "%d", cacheFilesParam);
1146 argv[argc++] = "-files";
1147 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1149 if (cacheStatEntriesParam) {
1150 snprintf(buf, sizeof(buf), "%d", cacheStatEntriesParam);
1152 argv[argc++] = "-stat";
1153 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1155 if (dCacheSizeParam) {
1156 snprintf(buf, sizeof(buf), "%d", dCacheSizeParam);
1158 argv[argc++] = "-dcache";
1159 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1161 if (vCacheSizeParam) {
1162 snprintf(buf, sizeof(buf), "%d", vCacheSizeParam);
1164 argv[argc++] = "-volumes";
1165 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1167 if (chunkSizeParam) {
1168 snprintf(buf, sizeof(buf), "%d", chunkSizeParam);
1170 argv[argc++] = "-chunksize";
1171 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1173 if (closeSynchParam) {
1174 argv[argc++] = "-waitclose";
1177 argv[argc++] = "-debug";
1179 if (nDaemonsParam) {
1180 snprintf(buf, sizeof(buf), "%d", nDaemonsParam);
1182 argv[argc++] = "-daemons";
1183 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1185 if (cacheFlagsParam) {
1186 if (cacheFlagsParam & AFSCALL_INIT_MEMCACHE) {
1187 argv[argc++] = "-memcache";
1191 argv[argc++] = "-logfile";
1192 argv[argc++] = logFile;
1197 code = uafs_ParseArgs(argc, argv);
1198 usr_assert(code == 0);
1200 for (i = 0; i < freeargc; i++) {
1205 usr_assert(code == 0);
1209 * Calculate the cacheMountDir used for a specified dir.
1211 * @param[in] dir Desired mount dir
1212 * @param[out] mountdir On success, contains the literal string that should
1213 * be used as the cache mount dir.
1214 * @param[in] size The number of bytes allocated in mountdir
1216 * @post On success, mountdir begins with a slash, and does not contain two
1217 * slashes adjacent to each other
1219 * @return operation status
1221 * @retval ENAMETOOLONG the specified dir is too long to fix in the given
1223 * @retval EINVAL the specified dir does not actually specify any meaningful
1227 calcMountDir(const char *dir, char *mountdir, size_t size)
1234 if (dir && strlen(dir) > size-1) {
1235 return ENAMETOOLONG;
1239 * Initialize the AFS mount point, default is '/afs'.
1240 * Strip duplicate/trailing slashes from mount point string.
1241 * afs_mountDirLen is set to strlen(afs_mountDir).
1246 sprintf(buf, "%s", dir);
1250 for (lastchar = '/', p = &buf[0]; *p != '\0'; p++) {
1251 if (lastchar != '/' || *p != '/') {
1252 mountdir[len++] = lastchar = *p;
1255 if (lastchar == '/' && len > 1)
1257 mountdir[len] = '\0';
1270 * Mount the AFS filesystem
1273 rc = afs_mount(&afs_RootVfs, NULL, NULL);
1274 usr_assert(rc == 0);
1275 rc = afs_root(&afs_RootVfs, &afs_RootVnode);
1276 usr_assert(rc == 0);
1280 * initialize the current directory to the AFS root
1282 afs_CurrentDir = afs_RootVnode;
1283 VN_HOLD(afs_CurrentDir);
1289 uafs_setMountDir(const char *dir)
1293 char tmp_mountDir[1024];
1295 rc = calcMountDir(dir, tmp_mountDir, sizeof(tmp_mountDir));
1297 afs_warn("Invalid mount dir specification (error %d): %s\n", rc, dir);
1299 if (strcmp(tmp_mountDir, afs_mountDir) != 0) {
1300 /* mount dir changed */
1301 strcpy(afs_mountDir, tmp_mountDir);
1302 afs_mountDirLen = strlen(afs_mountDir);
1309 uafs_statvfs(struct statvfs *buf)
1315 rc = afs_statvfs(&afs_RootVfs, buf);
1335 if (afs_CurrentDir) {
1336 VN_RELE(afs_CurrentDir);
1338 rc = afs_unmount(&afs_RootVfs);
1339 usr_assert(rc == 0);
1346 * Donate the current thread to the RX server pool.
1349 uafs_RxServerProc(void)
1353 struct rx_call *newcall = NULL;
1355 rxi_MorePackets(2); /* alloc more packets */
1356 threadID = rxi_availProcs++;
1359 sock = OSI_NULLSOCKET;
1360 rxi_ServerProc(threadID, newcall, &sock);
1361 if (sock == OSI_NULLSOCKET) {
1366 rxi_ListenerProc(sock, &threadID, &newcall);
1367 /* assert(threadID != -1); */
1368 /* assert(newcall != NULL); */
1372 struct syscallThreadArgs {
1382 syscallThread(void *argp)
1385 struct usr_ucred *crp;
1386 struct syscallThreadArgs *sysArgsP = (struct syscallThreadArgs *)argp;
1389 * AFS daemons run authenticated
1391 get_user_struct()->u_viceid = getuid();
1392 crp = get_user_struct()->u_cred;
1393 afs_set_cr_uid(crp, getuid());
1394 afs_set_cr_ruid(crp, getuid());
1395 crp->cr_suid = getuid();
1396 crp->cr_groups[0] = getgid();
1397 crp->cr_ngroups = 1;
1398 for (i = 1; i < NGROUPS; i++) {
1399 crp->cr_groups[i] = NOGROUP;
1402 call_syscall(sysArgsP->syscall, sysArgsP->afscall, sysArgsP->param1,
1403 sysArgsP->param2, sysArgsP->param3, sysArgsP->param4);
1405 afs_osi_Free(argp, -1);
1410 fork_syscall(long syscall, long afscall, long param1, long param2,
1411 long param3, long param4)
1414 struct syscallThreadArgs *sysArgsP;
1416 sysArgsP = (struct syscallThreadArgs *)
1417 afs_osi_Alloc(sizeof(struct syscallThreadArgs));
1418 usr_assert(sysArgsP != NULL);
1419 sysArgsP->syscall = syscall;
1420 sysArgsP->afscall = afscall;
1421 sysArgsP->param1 = param1;
1422 sysArgsP->param2 = param2;
1423 sysArgsP->param3 = param3;
1424 sysArgsP->param4 = param4;
1426 usr_thread_create(&tid, syscallThread, sysArgsP);
1427 usr_thread_detach(tid);
1432 call_syscall(long syscall, long afscall, long param1, long param2,
1433 long param3, long param4)
1445 a.syscall = syscall;
1446 a.afscall = afscall;
1452 get_user_struct()->u_error = 0;
1453 get_user_struct()->u_ap = (char *)&a;
1455 code = Afs_syscall();
1460 uafs_Setup(const char *mount)
1463 static int inited = 0;
1470 rc = calcMountDir(mount, afs_mountDir, sizeof(afs_mountDir));
1474 afs_mountDirLen = strlen(afs_mountDir);
1476 /* initialize global vars and such */
1479 /* initialize cache manager foo */
1486 uafs_ParseArgs(int argc, char **argv)
1488 return afsd_parse(argc, argv);
1500 return afsd_cacheMountDir;
1504 uafs_SetTokens(char *tbuffer, int tlen)
1507 struct afs_ioctl iob;
1512 iob.out = &outbuf[0];
1513 iob.out_size = sizeof(outbuf);
1515 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
1524 uafs_RPCStatsEnableProc(void)
1527 struct afs_ioctl iob;
1530 flag = AFSCALL_RXSTATS_ENABLE;
1531 iob.in = (char *)&flag;
1532 iob.in_size = sizeof(afs_int32);
1535 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1544 uafs_RPCStatsDisableProc(void)
1547 struct afs_ioctl iob;
1550 flag = AFSCALL_RXSTATS_DISABLE;
1551 iob.in = (char *)&flag;
1552 iob.in_size = sizeof(afs_int32);
1555 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1564 uafs_RPCStatsClearProc(void)
1567 struct afs_ioctl iob;
1570 flag = AFSCALL_RXSTATS_CLEAR;
1571 iob.in = (char *)&flag;
1572 iob.in_size = sizeof(afs_int32);
1575 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1584 uafs_RPCStatsEnablePeer(void)
1587 struct afs_ioctl iob;
1590 flag = AFSCALL_RXSTATS_ENABLE;
1591 iob.in = (char *)&flag;
1592 iob.in_size = sizeof(afs_int32);
1595 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1604 uafs_RPCStatsDisablePeer(void)
1607 struct afs_ioctl iob;
1610 flag = AFSCALL_RXSTATS_DISABLE;
1611 iob.in = (char *)&flag;
1612 iob.in_size = sizeof(afs_int32);
1615 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1624 uafs_RPCStatsClearPeer(void)
1627 struct afs_ioctl iob;
1630 flag = AFSCALL_RXSTATS_CLEAR;
1631 iob.in = (char *)&flag;
1632 iob.in_size = sizeof(afs_int32);
1635 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1644 * Lookup the target of a symbolic link
1645 * Call VN_HOLD on the output vnode if successful.
1646 * Returns zero on success, error code on failure.
1647 * If provided, use a path for confirming we are not linked to ourself.
1649 * Note: Caller must hold the AFS global lock.
1652 uafs_LookupLinkPath(struct usr_vnode *vp, struct usr_vnode *parentVp,
1653 char *ppathP, struct usr_vnode **vpp)
1658 struct usr_vnode *linkVp;
1660 struct iovec iov[1];
1664 pathP = afs_osi_Alloc(MAX_OSI_PATH + 1);
1665 usr_assert(pathP != NULL);
1668 * set up the uio buffer
1670 iov[0].iov_base = pathP;
1671 iov[0].iov_len = MAX_OSI_PATH + 1;
1672 uio.uio_iov = &iov[0];
1676 uio.uio_fmode = FREAD;
1677 uio.uio_resid = MAX_OSI_PATH + 1;
1680 * Read the link data
1682 code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
1684 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1687 len = MAX_OSI_PATH + 1 - uio.uio_resid;
1690 /* are we linked to ourname or ./ourname? ELOOP */
1692 if ((strcmp(pathP, ppathP) == 0) ||
1693 ((pathP[0] == '.') &&
1694 (pathP[1] == '/') &&
1695 (strcmp(&(pathP[2]), ppathP) == 0))) {
1701 * Find the target of the symbolic link
1703 code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
1705 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1709 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1715 * Lookup a file or directory given its path.
1716 * Call VN_HOLD on the output vnode if successful.
1717 * Returns zero on success, error code on failure.
1719 * Note: Caller must hold the AFS global lock.
1722 uafs_LookupName(char *path, struct usr_vnode *parentVp,
1723 struct usr_vnode **vpp, int follow, int no_eval_mtpt)
1727 struct usr_vnode *vp;
1728 struct usr_vnode *nextVp;
1729 struct usr_vnode *linkVp;
1730 struct vcache *nextVc;
1733 char *nextPathP = NULL;
1738 * Absolute paths must start with the AFS mount point.
1740 if (path[0] != '/') {
1743 path = uafs_afsPathName(path);
1751 * Loop through the path looking for the new directory
1753 tmpPath = afs_osi_Alloc(strlen(path) + 1);
1754 usr_assert(tmpPath != NULL);
1755 strcpy(tmpPath, path);
1758 while (pathP != NULL && *pathP != '\0') {
1759 usr_assert(*pathP != '/');
1762 * terminate the current component and skip over slashes
1764 nextPathP = afs_strchr(pathP, '/');
1765 if (nextPathP != NULL) {
1766 while (*nextPathP == '/') {
1767 *(nextPathP++) = '\0';
1772 * Don't call afs_lookup on non-directories
1774 if (vp->v_type != VDIR) {
1776 afs_osi_Free(tmpPath, strlen(path) + 1);
1780 if (vp == afs_RootVnode && strcmp(pathP, "..") == 0) {
1782 * The AFS root is its own parent
1784 nextVp = afs_RootVnode;
1787 * We need execute permission to search a directory
1789 code = afs_access(VTOAFS(vp), VEXEC, get_user_struct()->u_cred);
1792 afs_osi_Free(tmpPath, strlen(path) + 1);
1797 * lookup the next component in the path, we can release the
1798 * subdirectory since we hold the global lock
1802 if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
1803 code = afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred, 0);
1806 afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred,
1809 nextVp=AFSTOV(nextVc);
1812 afs_osi_Free(tmpPath, strlen(path) + 1);
1818 * Follow symbolic links for parent directories and
1819 * for leaves when the follow flag is set.
1821 if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
1823 while (nextVp->v_type == VLNK) {
1824 if (++linkCount > MAX_OSI_LINKS) {
1827 afs_osi_Free(tmpPath, strlen(path) + 1);
1830 code = uafs_LookupLinkPath(nextVp, vp, NULL, &linkVp);
1834 afs_osi_Free(tmpPath, strlen(path) + 1);
1848 * Special case, nextPathP is non-null if pathname ends in slash
1850 if (nextPathP != NULL && vp->v_type != VDIR) {
1852 afs_osi_Free(tmpPath, strlen(path) + 1);
1856 afs_osi_Free(tmpPath, strlen(path) + 1);
1862 uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentVp,
1863 struct usr_vnode **vpp)
1865 return uafs_LookupLinkPath(vp, parentVp, NULL, vpp);
1869 * Lookup the parent of a file or directory given its path
1870 * Call VN_HOLD on the output vnode if successful.
1871 * Returns zero on success, error code on failure.
1873 * Note: Caller must hold the AFS global lock.
1876 uafs_LookupParent(char *path, struct usr_vnode **vpp)
1881 struct usr_vnode *parentP;
1886 * Absolute path names must start with the AFS mount point.
1889 pathP = uafs_afsPathName(path);
1890 if (pathP == NULL) {
1896 * Find the length of the parent path
1899 while (len > 0 && path[len - 1] == '/') {
1905 while (len > 0 && path[len - 1] != '/') {
1912 pathP = afs_osi_Alloc(len);
1913 usr_assert(pathP != NULL);
1914 memcpy(pathP, path, len - 1);
1915 pathP[len - 1] = '\0';
1918 * look up the parent
1920 code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
1921 afs_osi_Free(pathP, len);
1925 if (parentP->v_type != VDIR) {
1935 * Return a pointer to the first character in the last component
1939 uafs_LastPath(char *path)
1944 while (len > 0 && path[len - 1] == '/') {
1947 while (len > 0 && path[len - 1] != '/') {
1957 * Set the working directory.
1960 uafs_chdir(char *path)
1964 retval = uafs_chdir_r(path);
1970 uafs_chdir_r(char *path)
1975 code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
1980 if (dirP->v_type != VDIR) {
1985 VN_RELE(afs_CurrentDir);
1986 afs_CurrentDir = dirP;
1991 * Create a directory.
1994 uafs_mkdir(char *path, int mode)
1998 retval = uafs_mkdir_r(path, mode);
2004 uafs_mkdir_r(char *path, int mode)
2008 struct vnode *parentP;
2009 struct vcache *dirP;
2010 struct usr_vattr attrs;
2012 if (uafs_IsRoot(path)) {
2017 * Look up the parent directory.
2019 nameP = uafs_LastPath(path);
2020 if (nameP != NULL) {
2021 code = uafs_LookupParent(path, &parentP);
2027 parentP = afs_CurrentDir;
2033 * Make sure the directory has at least one character
2035 if (*nameP == '\0') {
2042 * Create the directory
2044 usr_vattr_null(&attrs);
2045 attrs.va_type = VREG;
2046 attrs.va_mode = mode;
2047 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2048 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2050 code = afs_mkdir(VTOAFS(parentP), nameP, &attrs, &dirP, get_user_struct()->u_cred);
2056 VN_RELE(AFSTOV(dirP));
2061 * Return 1 if path is the AFS root, otherwise return 0
2064 uafs_IsRoot(char *path)
2066 while (*path == '/' && *(path + 1) == '/') {
2069 if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2072 path += afs_mountDirLen;
2073 while (*path == '/') {
2076 if (*path != '\0') {
2084 * Note: file name may not end in a slash.
2087 uafs_open(char *path, int flags, int mode)
2091 retval = uafs_open_r(path, flags, mode);
2097 uafs_open_r(char *path, int flags, int mode)
2103 struct usr_vnode *fileP;
2104 struct usr_vnode *dirP;
2105 struct usr_vattr attrs;
2110 if (uafs_IsRoot(path)) {
2111 fileP = afs_RootVnode;
2115 * Look up the parent directory.
2117 nameP = uafs_LastPath(path);
2118 if (nameP != NULL) {
2119 code = uafs_LookupParent(path, &dirP);
2125 dirP = afs_CurrentDir;
2131 * Make sure the filename has at least one character
2133 if (*nameP == '\0') {
2140 * Get the VNODE for this file
2142 if (flags & O_CREAT) {
2143 usr_vattr_null(&attrs);
2144 attrs.va_type = VREG;
2145 attrs.va_mode = mode;
2146 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2147 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2148 if (flags & O_TRUNC) {
2154 afs_create(VTOAFS(dirP), nameP, &attrs,
2155 (flags & O_EXCL) ? usr_EXCL : usr_NONEXCL, mode,
2156 &vc, get_user_struct()->u_cred);
2165 code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2173 * Check whether we have access to this file
2176 if (flags & (O_RDONLY | O_RDWR)) {
2179 if (flags & (O_WRONLY | O_RDWR)) {
2183 fileMode = VREAD; /* since O_RDONLY is 0 */
2184 code = afs_access(VTOAFS(fileP), fileMode, get_user_struct()->u_cred);
2192 * Get the file attributes, all we need is the size
2194 code = afs_getattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2204 * Setup the open flags
2207 if (flags & O_TRUNC) {
2208 openFlags |= FTRUNC;
2210 if (flags & O_APPEND) {
2211 openFlags |= FAPPEND;
2213 if (flags & O_SYNC) {
2216 if (flags & O_SYNC) {
2219 if (flags & (O_RDONLY | O_RDWR)) {
2222 if (flags & (O_WRONLY | O_RDWR)) {
2223 openFlags |= FWRITE;
2225 if ((openFlags & (FREAD | FWRITE)) == 0) {
2226 /* O_RDONLY is 0, so ... */
2231 * Truncate if necessary
2233 if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2234 usr_vattr_null(&attrs);
2235 attrs.va_mask = ATTR_SIZE;
2237 code = afs_setattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2249 code = afs_open(&vc, openFlags, get_user_struct()->u_cred);
2257 * Put the vnode pointer into the file table
2259 for (fd = 0; fd < MAX_OSI_FILES; fd++) {
2260 if (afs_FileTable[fd] == NULL) {
2261 afs_FileTable[fd] = fileP;
2262 afs_FileFlags[fd] = openFlags;
2263 if (flags & O_APPEND) {
2264 afs_FileOffsets[fd] = attrs.va_size;
2266 afs_FileOffsets[fd] = 0;
2271 if (fd == MAX_OSI_FILES) {
2284 uafs_creat(char *path, int mode)
2287 rc = uafs_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2292 uafs_creat_r(char *path, int mode)
2295 rc = uafs_open_r(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2303 uafs_write(int fd, char *buf, int len)
2307 retval = uafs_pwrite_r(fd, buf, len, afs_FileOffsets[fd]);
2313 uafs_pwrite(int fd, char *buf, int len, off_t offset)
2317 retval = uafs_pwrite_r(fd, buf, len, offset);
2323 uafs_pwrite_r(int fd, char *buf, int len, off_t offset)
2327 struct iovec iov[1];
2328 struct usr_vnode *fileP;
2331 * Make sure this is an open file
2333 fileP = afs_FileTable[fd];
2334 if (fileP == NULL) {
2340 * set up the uio buffer
2342 iov[0].iov_base = buf;
2343 iov[0].iov_len = len;
2344 uio.uio_iov = &iov[0];
2346 uio.uio_offset = offset;
2348 uio.uio_fmode = FWRITE;
2349 uio.uio_resid = len;
2355 code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], get_user_struct()->u_cred, 0);
2361 afs_FileOffsets[fd] = uio.uio_offset;
2362 return (len - uio.uio_resid);
2369 uafs_read(int fd, char *buf, int len)
2373 retval = uafs_pread_r(fd, buf, len, afs_FileOffsets[fd]);
2379 uafs_pread_nocache(int fd, char *buf, int len, off_t offset)
2383 retval = uafs_pread_nocache_r(fd, buf, len, offset);
2389 uafs_pread_nocache_r(int fd, char *buf, int len, off_t offset)
2392 struct iovec iov[1];
2393 struct usr_vnode *fileP;
2394 struct nocache_read_request *bparms;
2398 * Make sure this is an open file
2400 fileP = afs_FileTable[fd];
2401 if (fileP == NULL) {
2406 /* these get freed in PrefetchNoCache, so... */
2407 bparms = afs_osi_Alloc(sizeof(struct nocache_read_request));
2408 bparms->areq = afs_osi_Alloc(sizeof(struct vrequest));
2410 code = afs_InitReq(bparms->areq, get_user_struct()->u_cred);
2412 afs_osi_Free(bparms->areq, sizeof(struct vrequest));
2413 afs_osi_Free(bparms, sizeof(struct nocache_read_request));
2418 bparms->auio = &uio;
2419 bparms->offset = offset;
2420 bparms->length = len;
2423 * set up the uio buffer
2425 iov[0].iov_base = buf;
2426 iov[0].iov_len = len;
2427 uio.uio_iov = &iov[0];
2429 uio.uio_offset = offset;
2431 uio.uio_fmode = FREAD;
2432 uio.uio_resid = len;
2437 code = afs_PrefetchNoCache(VTOAFS(fileP), get_user_struct()->u_cred,
2445 afs_FileOffsets[fd] = uio.uio_offset;
2446 return (len - uio.uio_resid);
2450 uafs_pread(int fd, char *buf, int len, off_t offset)
2454 retval = uafs_pread_r(fd, buf, len, offset);
2460 uafs_pread_r(int fd, char *buf, int len, off_t offset)
2464 struct iovec iov[1];
2465 struct usr_vnode *fileP;
2468 * Make sure this is an open file
2470 fileP = afs_FileTable[fd];
2471 if (fileP == NULL) {
2477 * set up the uio buffer
2479 iov[0].iov_base = buf;
2480 iov[0].iov_len = len;
2481 uio.uio_iov = &iov[0];
2483 uio.uio_offset = offset;
2485 uio.uio_fmode = FREAD;
2486 uio.uio_resid = len;
2491 code = afs_read(VTOAFS(fileP), &uio, get_user_struct()->u_cred, 0);
2497 afs_FileOffsets[fd] = uio.uio_offset;
2498 return (len - uio.uio_resid);
2502 * Copy the attributes of a file into a stat structure.
2504 * NOTE: Caller must hold the global AFS lock.
2507 uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2510 struct usr_vattr attrs;
2515 * Get the attributes
2517 code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2523 * Copy the attributes, zero fields that aren't set
2525 memset((void *)stats, 0, sizeof(struct stat));
2527 stats->st_ino = attrs.va_nodeid;
2528 stats->st_mode = attrs.va_mode;
2529 stats->st_nlink = attrs.va_nlink;
2530 stats->st_uid = attrs.va_uid;
2531 stats->st_gid = attrs.va_gid;
2532 stats->st_rdev = attrs.va_rdev;
2533 stats->st_size = attrs.va_size;
2534 stats->st_atime = attrs.va_atime.tv_sec;
2535 stats->st_mtime = attrs.va_mtime.tv_sec;
2536 stats->st_ctime = attrs.va_ctime.tv_sec;
2537 /* preserve dv if possible */
2538 #if defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
2539 stats->st_atimespec.tv_nsec = attrs.va_atime.tv_usec * 1000;
2540 stats->st_mtimespec.tv_nsec = attrs.va_mtime.tv_usec * 1000;
2541 stats->st_ctimespec.tv_nsec = attrs.va_ctime.tv_usec * 1000;
2542 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
2543 stats->st_atimensec = attrs.va_atime.tv_usec * 1000;
2544 stats->st_mtimensec = attrs.va_mtime.tv_usec * 1000;
2545 stats->st_ctimensec = attrs.va_ctime.tv_usec * 1000;
2547 stats->st_blksize = attrs.va_blocksize;
2548 stats->st_blocks = attrs.va_blocks;
2554 * Get the attributes of a file, do follow links
2557 uafs_stat(char *path, struct stat *buf)
2561 retval = uafs_stat_r(path, buf);
2567 uafs_stat_r(char *path, struct stat *buf)
2572 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2577 code = uafs_GetAttr(vp, buf);
2587 * Get the attributes of a file, don't follow links
2590 uafs_lstat(char *path, struct stat *buf)
2594 retval = uafs_lstat_r(path, buf);
2600 uafs_lstat_r(char *path, struct stat *buf)
2605 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
2610 code = uafs_GetAttr(vp, buf);
2620 * Get the attributes of an open file
2623 uafs_fstat(int fd, struct stat *buf)
2627 retval = uafs_fstat_r(fd, buf);
2633 uafs_fstat_r(int fd, struct stat *buf)
2638 vp = afs_FileTable[fd];
2643 code = uafs_GetAttr(vp, buf);
2652 * change the permissions on a file
2655 uafs_chmod(char *path, int mode)
2659 retval = uafs_chmod_r(path, mode);
2665 uafs_chmod_r(char *path, int mode)
2669 struct usr_vattr attrs;
2671 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2676 usr_vattr_null(&attrs);
2677 attrs.va_mask = ATTR_MODE;
2678 attrs.va_mode = mode;
2679 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2689 * change the permissions on an open file
2692 uafs_fchmod(int fd, int mode)
2696 retval = uafs_fchmod_r(fd, mode);
2702 uafs_fchmod_r(int fd, int mode)
2706 struct usr_vattr attrs;
2708 vp = afs_FileTable[fd];
2713 usr_vattr_null(&attrs);
2714 attrs.va_mask = ATTR_MODE;
2715 attrs.va_mode = mode;
2716 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2728 uafs_truncate(char *path, int length)
2732 retval = uafs_truncate_r(path, length);
2738 uafs_truncate_r(char *path, int length)
2742 struct usr_vattr attrs;
2744 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2749 usr_vattr_null(&attrs);
2750 attrs.va_mask = ATTR_SIZE;
2751 attrs.va_size = length;
2752 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2762 * truncate an open file
2765 uafs_ftruncate(int fd, int length)
2769 retval = uafs_ftruncate_r(fd, length);
2775 uafs_ftruncate_r(int fd, int length)
2779 struct usr_vattr attrs;
2781 vp = afs_FileTable[fd];
2786 usr_vattr_null(&attrs);
2787 attrs.va_mask = ATTR_SIZE;
2788 attrs.va_size = length;
2789 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2798 * set the read/write file pointer of an open file
2801 uafs_lseek(int fd, int offset, int whence)
2805 retval = uafs_lseek_r(fd, offset, whence);
2811 uafs_lseek_r(int fd, int offset, int whence)
2815 struct usr_vattr attrs;
2816 struct usr_vnode *vp;
2818 vp = afs_FileTable[fd];
2825 newpos = afs_FileOffsets[fd] + offset;
2831 code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2836 newpos = attrs.va_size + offset;
2846 afs_FileOffsets[fd] = newpos;
2858 retval = uafs_fsync_r(fd);
2864 uafs_fsync_r(int fd)
2867 struct usr_vnode *fileP;
2870 fileP = afs_FileTable[fd];
2871 if (fileP == NULL) {
2876 code = afs_fsync(VTOAFS(fileP), get_user_struct()->u_cred);
2893 retval = uafs_close_r(fd);
2899 uafs_close_r(int fd)
2902 struct usr_vnode *fileP;
2904 fileP = afs_FileTable[fd];
2905 if (fileP == NULL) {
2909 afs_FileTable[fd] = NULL;
2911 code = afs_close(VTOAFS(fileP), afs_FileFlags[fd], get_user_struct()->u_cred);
2922 * Create a hard link from the source to the target
2923 * Note: file names may not end in a slash.
2926 uafs_link(char *existing, char *new)
2930 retval = uafs_link_r(existing, new);
2936 uafs_link_r(char *existing, char *new)
2939 struct usr_vnode *existP;
2940 struct usr_vnode *dirP;
2943 if (uafs_IsRoot(new)) {
2948 * Look up the existing node.
2950 code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
2957 * Look up the parent directory.
2959 nameP = uafs_LastPath(new);
2960 if (nameP != NULL) {
2961 code = uafs_LookupParent(new, &dirP);
2968 dirP = afs_CurrentDir;
2974 * Make sure the filename has at least one character
2976 if (*nameP == '\0') {
2986 code = afs_link(VTOAFS(existP), VTOAFS(dirP), nameP, get_user_struct()->u_cred);
2997 * Create a symbolic link from the source to the target
2998 * Note: file names may not end in a slash.
3001 uafs_symlink(char *target, char *source)
3005 retval = uafs_symlink_r(target, source);
3011 uafs_symlink_r(char *target, char *source)
3014 struct usr_vnode *dirP;
3015 struct usr_vattr attrs;
3018 if (uafs_IsRoot(source)) {
3023 * Look up the parent directory.
3025 nameP = uafs_LastPath(source);
3026 if (nameP != NULL) {
3027 code = uafs_LookupParent(source, &dirP);
3033 dirP = afs_CurrentDir;
3039 * Make sure the filename has at least one character
3041 if (*nameP == '\0') {
3050 usr_vattr_null(&attrs);
3051 attrs.va_type = VLNK;
3052 attrs.va_mode = 0777;
3053 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
3054 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
3055 code = afs_symlink(VTOAFS(dirP), nameP, &attrs, target, NULL,
3056 get_user_struct()->u_cred);
3066 * Read a symbolic link into the buffer
3069 uafs_readlink(char *path, char *buf, int len)
3073 retval = uafs_readlink_r(path, buf, len);
3079 uafs_readlink_r(char *path, char *buf, int len)
3082 struct usr_vnode *vp;
3084 struct iovec iov[1];
3086 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3092 if (vp->v_type != VLNK) {
3099 * set up the uio buffer
3101 iov[0].iov_base = buf;
3102 iov[0].iov_len = len;
3103 uio.uio_iov = &iov[0];
3107 uio.uio_fmode = FREAD;
3108 uio.uio_resid = len;
3113 code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3121 * return the number of bytes read
3123 return (len - uio.uio_resid);
3127 * Remove a file (or directory)
3128 * Note: file name may not end in a slash.
3131 uafs_unlink(char *path)
3135 retval = uafs_unlink_r(path);
3141 uafs_unlink_r(char *path)
3144 struct usr_vnode *dirP;
3147 if (uafs_IsRoot(path)) {
3152 * Look up the parent directory.
3154 nameP = uafs_LastPath(path);
3155 if (nameP != NULL) {
3156 code = uafs_LookupParent(path, &dirP);
3162 dirP = afs_CurrentDir;
3168 * Make sure the filename has at least one character
3170 if (*nameP == '\0') {
3179 code = afs_remove(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3190 * Rename a file (or directory)
3193 uafs_rename(char *old, char *new)
3197 retval = uafs_rename_r(old, new);
3203 uafs_rename_r(char *old, char *new)
3208 struct usr_vnode *odirP;
3209 struct usr_vnode *ndirP;
3211 if (uafs_IsRoot(new)) {
3216 * Look up the parent directories.
3218 onameP = uafs_LastPath(old);
3219 if (onameP != NULL) {
3220 code = uafs_LookupParent(old, &odirP);
3226 odirP = afs_CurrentDir;
3230 nnameP = uafs_LastPath(new);
3231 if (nnameP != NULL) {
3232 code = uafs_LookupParent(new, &ndirP);
3238 ndirP = afs_CurrentDir;
3244 * Make sure the filename has at least one character
3246 if (*onameP == '\0' || *nnameP == '\0') {
3256 code = afs_rename(VTOAFS(odirP), onameP, VTOAFS(ndirP), nnameP, get_user_struct()->u_cred);
3268 * Remove a or directory
3269 * Note: file name may not end in a slash.
3272 uafs_rmdir(char *path)
3276 retval = uafs_rmdir_r(path);
3282 uafs_rmdir_r(char *path)
3285 struct usr_vnode *dirP;
3288 if (uafs_IsRoot(path)) {
3293 * Look up the parent directory.
3295 nameP = uafs_LastPath(path);
3296 if (nameP != NULL) {
3297 code = uafs_LookupParent(path, &dirP);
3303 dirP = afs_CurrentDir;
3309 * Make sure the directory name has at least one character
3311 if (*nameP == '\0') {
3318 * Remove the directory
3320 code = afs_rmdir(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3331 * Flush a file from the AFS cache
3334 uafs_FlushFile(char *path)
3337 struct afs_ioctl iob;
3345 call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6), (long)&iob, 0,
3356 uafs_FlushFile_r(char *path)
3360 retval = uafs_FlushFile(path);
3369 uafs_opendir(char *path)
3373 retval = uafs_opendir_r(path);
3379 uafs_opendir_r(char *path)
3382 struct usr_vnode *fileP;
3386 * Open the directory for reading
3388 fd = uafs_open_r(path, O_RDONLY, 0);
3393 fileP = afs_FileTable[fd];
3394 if (fileP == NULL) {
3398 if (fileP->v_type != VDIR) {
3405 * Set up the directory structures
3407 dirp = afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3408 sizeof(struct usr_dirent));
3409 usr_assert(dirp != NULL);
3410 dirp->dd_buf = (char *)(dirp + 1);
3420 * Read directory entries into a file system independent format.
3421 * This routine was developed to support AFS cache consistency testing.
3422 * You should use uafs_readdir instead.
3425 uafs_getdents(int fd, struct min_direct *buf, int len)
3429 retval = uafs_getdents_r(fd, buf, len);
3435 uafs_getdents_r(int fd, struct min_direct *buf, int len)
3439 struct usr_vnode *vp;
3440 struct iovec iov[1];
3443 * Make sure this is an open file
3445 vp = afs_FileTable[fd];
3453 * set up the uio buffer
3455 iov[0].iov_base = (char *)buf;
3456 iov[0].iov_len = len;
3457 uio.uio_iov = &iov[0];
3459 uio.uio_offset = afs_FileOffsets[fd];
3461 uio.uio_fmode = FREAD;
3462 uio.uio_resid = len;
3465 * read the next chunk from the directory
3467 code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3473 afs_FileOffsets[fd] = uio.uio_offset;
3474 return (len - uio.uio_resid);
3478 * read from a directory (names only)
3481 uafs_readdir(usr_DIR * dirp)
3483 struct usr_dirent *retval;
3485 retval = uafs_readdir_r(dirp);
3491 uafs_readdir_r(usr_DIR * dirp)
3496 struct usr_vnode *vp;
3497 struct iovec iov[1];
3498 struct usr_dirent *direntP;
3499 struct min_direct *directP;
3507 * Make sure this is an open file
3509 vp = afs_FileTable[dirp->dd_fd];
3516 * If there are no entries in the stream buffer
3517 * then read another chunk
3519 directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3520 if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3522 * set up the uio buffer
3524 iov[0].iov_base = dirp->dd_buf;
3525 iov[0].iov_len = USR_DIRSIZE;
3526 uio.uio_iov = &iov[0];
3528 uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3530 uio.uio_fmode = FREAD;
3531 uio.uio_resid = USR_DIRSIZE;
3534 * read the next chunk from the directory
3536 code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3541 afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3543 dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3545 directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3549 * Check for end of file
3551 if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3555 len = ((sizeof(struct min_direct) + directP->d_namlen + 4) & (~3));
3556 usr_assert(len <= dirp->dd_size);
3559 * Copy the next entry into the usr_dirent structure and advance
3561 direntP = (struct usr_dirent *)(dirp->dd_buf + USR_DIRSIZE);
3562 direntP->d_ino = directP->d_fileno;
3563 direntP->d_off = direntP->d_reclen;
3565 sizeof(struct usr_dirent) - MAXNAMLEN + directP->d_namlen + 1;
3566 memcpy(&direntP->d_name[0], (void *)(directP + 1), directP->d_namlen);
3567 direntP->d_name[directP->d_namlen] = '\0';
3568 dirp->dd_loc += len;
3569 dirp->dd_size -= len;
3578 uafs_closedir(usr_DIR * dirp)
3582 retval = uafs_closedir_r(dirp);
3588 uafs_closedir_r(usr_DIR * dirp)
3599 afs_osi_Free((char *)dirp,
3600 sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
3601 rc = uafs_close_r(fd);
3606 * Destroy AFS credentials from the kernel cache
3613 usr_mutex_lock(&osi_authenticate_lock);
3614 code = ktc_ForgetAllTokens();
3615 usr_mutex_unlock(&osi_authenticate_lock);
3624 retval = uafs_unlog();
3630 * Strip the AFS mount point from a pathname string. Return
3631 * NULL if the path is a relative pathname or if the path
3632 * doesn't start with the AFS mount point string.
3635 uafs_afsPathName(char *path)
3644 for (i = 1, p = path + 1; *p != '\0'; p++) {
3645 /* Ignore duplicate slashes */
3646 if (*p == '/' && lastchar == '/')
3648 /* Is this a subdirectory of the AFS mount point? */
3649 if (afs_mountDir[i] == '\0' && *p == '/') {
3650 /* strip leading slashes */
3651 while (*(++p) == '/');
3654 /* Reject paths that are not within AFS */
3655 if (*p != afs_mountDir[i])
3660 /* Is this the AFS mount point? */
3661 if (afs_mountDir[i] == '\0') {
3662 usr_assert(*p == '\0');
3669 * uafs_getcellstatus
3670 * get the cell status
3673 uafs_getcellstatus(char *cell, afs_int32 * status)
3676 struct afs_ioctl iob;
3679 iob.in_size = strlen(cell) + 1;
3683 rc = call_syscall(AFSCALL_PIOCTL, /*path */ 0, _VICEIOCTL(35),
3691 *status = (intptr_t)iob.out;
3697 * Get quota of volume associated with path
3700 uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
3703 struct afs_ioctl iob;
3704 VolumeStatus status;
3708 iob.out = (char *)&status;
3709 iob.out_size = sizeof status;
3711 rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
3719 *BlocksInUse = status.BlocksInUse;
3720 *MaxQuota = status.MaxQuota;
3726 * Set quota of volume associated with path
3729 uafs_setvolquota(char *path, afs_int32 MaxQuota)
3732 struct afs_ioctl iob;
3733 VolumeStatus status = { 0 };
3735 iob.in = (char *)&status;
3736 iob.in_size = sizeof status;
3740 status.MaxQuota = MaxQuota;
3741 status.MinQuota = -1;
3743 rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
3755 * uafs_statmountpoint
3756 * Determine whether a dir. is a mount point or not
3757 * return 1 if mount point, 0 if not
3760 uafs_statmountpoint(char *path)
3765 retval = uafs_statmountpoint_r(path);
3771 uafs_statmountpoint_r(char *path)
3778 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
3793 * Get a list of rights for the current user on path.
3796 uafs_access(char *path, int flags)
3813 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3820 code = afs_access(VTOAFS(vp), fileMode, get_user_struct()->u_cred);
3827 return code ? -1 : 0;
3832 * Get a list of rights for the current user on path.
3835 uafs_getRights(char *path)
3842 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3850 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
3851 | PRSFS_LOCK | PRSFS_ADMINISTER;
3853 afs_rights = afs_getRights(VTOAFS(vp), afs_rights, get_user_struct()->u_cred);
3858 #endif /* UKERNEL */