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/kauth.h"
30 #include "afs/kautils.h"
31 #include "afs/afsutil.h"
32 #include "afs/afs_bypasscache.h"
33 #include "rx/rx_globals.h"
34 #include "afsd/afsd.h"
40 #ifndef AFS_CACHE_VNODE_PATH
41 #error You must compile UKERNEL code with -DAFS_CACHE_VNODE_PATH
44 #define CACHEINFOFILE "cacheinfo"
45 #define AFSLOGFILE "AFSLog"
46 #define DCACHEFILE "CacheItems"
47 #define VOLINFOFILE "VolumeItems"
48 #define CELLINFOFILE "CellItems"
52 #define MIN(A,B) ((A)<(B)?(A):(B))
55 #define MAX(A,B) ((A)>(B)?(A):(B))
58 extern int cacheDiskType;
60 char afs_LclCellName[64];
62 static struct usr_vnode *afs_FileTable[MAX_OSI_FILES];
63 static int afs_FileFlags[MAX_OSI_FILES];
64 static off_t afs_FileOffsets[MAX_OSI_FILES];
66 #define MAX_CACHE_LOOPS 4
68 static struct usr_vfs afs_RootVfs;
69 static struct usr_vnode *afs_RootVnode = NULL;
70 static struct usr_vnode *afs_CurrentDir = NULL;
72 static char afs_mountDir[1024]; /* AFS mount point */
73 static int afs_mountDirLen; /* strlen of AFS mount point */
75 struct afsconf_dir *afs_cdir; /* config dir */
77 int afs_bufferpages = 100;
79 static usr_key_t afs_global_u_key;
81 static struct usr_proc *afs_global_procp = NULL;
82 static struct usr_ucred *afs_global_ucredp = NULL;
84 struct usr_ucred afs_osi_cred, *afs_osi_credp;
85 usr_mutex_t afs_global_lock;
86 usr_thread_t afs_global_owner;
87 usr_mutex_t rx_global_lock;
88 usr_thread_t rx_global_owner;
90 static usr_mutex_t osi_dummy_lock;
91 static usr_mutex_t osi_waitq_lock;
92 static usr_mutex_t osi_authenticate_lock;
94 afs_lock_t osi_flplock;
95 afs_lock_t osi_fsplock;
98 * Mutex and condition variable used to implement sleep
100 pthread_mutex_t usr_sleep_mutex;
101 pthread_cond_t usr_sleep_cond;
103 int call_syscall(long, long, long, long, long, long);
104 int fork_syscall(long, long, long, long, long, long);
108 * Hash table mapping addresses onto wait structures for
109 * osi_Sleep/osi_Wakeup and osi_Wait/osi_Wakeup
111 typedef struct osi_wait {
115 struct osi_wait *next;
116 struct osi_wait *prev;
118 struct osi_wait *timedNext;
119 struct osi_wait *timedPrev;
123 * Head of the linked list of available waitq structures.
125 static osi_wait_t *osi_waithash_avail;
128 * List of timed waits, NSAPI does not provide a cond_timed
129 * wait, so we need to keep track of the timed waits ourselves and
130 * periodically check for expirations
132 static osi_wait_t *osi_timedwait_head;
133 static osi_wait_t *osi_timedwait_tail;
138 } osi_waithash_table[OSI_WAITHASH_SIZE];
141 * Never call afs_brelse
144 ufs_brelse(struct usr_vnode *vp, struct usr_buf *bp)
151 * I am not sure what to do with these, they assert for now
154 iodone(struct usr_buf *bp)
168 * Every user is a super user
171 afs_osi_suser(void *credp)
177 afs_suser(void *credp)
183 * These are no-ops in user space
187 afs_osi_SetTime(osi_timeval_t * atv)
193 * xflock should never fall through, the only files we know
194 * about are AFS files
204 * ioctl should never fall through, the only files we know
205 * about are AFS files
215 * We do not support the inode related system calls
218 afs_syscall_icreate(long a, long b, long c, long d, long e, long f)
225 afs_syscall_iincdec(int dev, int inode, int inode_p1, int amount)
232 afs_syscall_iopen(int dev, int inode, int usrmod)
239 afs_syscall_ireadwrite(void)
246 * these routines are referenced in the vfsops structure, but
247 * should never get called
278 * uiomove copies data between kernel buffers and uio buffers
281 usr_uiomove(char *kbuf, int n, int rw, struct usr_uio *uio)
288 nio = uio->uio_iovcnt;
298 while (nio > 0 && n > 0) {
299 len = MIN(n, iovp->iov_len);
300 if (rw == UIO_READ) {
301 memcpy(iovp->iov_base, ptr, len);
303 memcpy(ptr, iovp->iov_base, len);
307 uio->uio_resid -= len;
308 uio->uio_offset += len;
309 iovp->iov_base = (char *)(iovp->iov_base) + len;
310 iovp->iov_len -= len;
321 * routines to manage user credentials
324 usr_crcopy(struct usr_ucred *credp)
326 struct usr_ucred *newcredp;
328 newcredp = afs_osi_Alloc(sizeof(struct usr_ucred));
330 newcredp->cr_ref = 1;
337 struct usr_ucred *newcredp;
339 newcredp = afs_osi_Alloc(sizeof(struct usr_ucred));
340 newcredp->cr_ref = 1;
345 usr_crfree(struct usr_ucred *credp)
348 if (credp->cr_ref == 0) {
349 afs_osi_Free((char *)credp, sizeof(struct usr_ucred));
355 usr_crhold(struct usr_ucred *credp)
362 usr_vattr_null(struct usr_vattr *vap)
367 n = sizeof(struct usr_vattr);
375 * Initialize the thread specific data used to simulate the
376 * kernel environment for each thread. The user structure
377 * is stored in the thread specific data.
380 uafs_InitThread(void)
383 struct usr_user *uptr;
386 * initialize the thread specific user structure. Use malloc to
387 * allocate the data block, so pthread_finish can free the buffer
388 * when this thread terminates.
390 uptr = malloc(sizeof(struct usr_user) + sizeof(struct usr_ucred));
391 usr_assert(uptr != NULL);
394 uptr->u_procp = afs_global_procp;
395 uptr->u_cred = (struct usr_ucred *)(uptr + 1);
396 *uptr->u_cred = *afs_global_ucredp;
397 st = usr_setspecific(afs_global_u_key, (void *)uptr);
402 * routine to get the user structure from the thread specific data.
403 * this routine is used to implement the global 'u' structure. Initializes
404 * the thread if needed.
407 get_user_struct(void)
409 struct usr_user *uptr;
412 st = usr_getspecific(afs_global_u_key, &uptr);
416 st = usr_getspecific(afs_global_u_key, &uptr);
418 usr_assert(uptr != NULL);
424 * Hash an address for the waithash table
426 #define WAITHASH(X) \
427 (((long)(X)^((long)(X)>>4)^((long)(X)<<4))&(OSI_WAITHASH_SIZE-1))
433 afs_osi_Sleep(void *x)
437 int glockOwner = ISAFS_GLOCK();
439 usr_mutex_lock(&osi_waitq_lock);
444 if (osi_waithash_avail == NULL) {
445 waitp = afs_osi_Alloc(sizeof(osi_wait_t));
446 usr_cond_init(&waitp->cond);
448 waitp = osi_waithash_avail;
449 osi_waithash_avail = osi_waithash_avail->next;
453 DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
454 osi_waithash_table[index].tail, next, prev);
455 waitp->expiration = 0;
456 waitp->timedNext = NULL;
457 waitp->timedPrev = NULL;
458 while (waitp->flag == 0) {
459 usr_cond_wait(&waitp->cond, &osi_waitq_lock);
461 DLL_DELETE(waitp, osi_waithash_table[index].head,
462 osi_waithash_table[index].tail, next, prev);
463 waitp->next = osi_waithash_avail;
464 osi_waithash_avail = waitp;
465 usr_mutex_unlock(&osi_waitq_lock);
472 afs_osi_SleepSig(void *x)
479 afs_osi_Wakeup(void *x)
485 usr_mutex_lock(&osi_waitq_lock);
486 waitp = osi_waithash_table[index].head;
488 if (waitp->addr == x && waitp->flag == 0) {
490 usr_cond_signal(&waitp->cond);
494 usr_mutex_unlock(&osi_waitq_lock);
499 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
501 return afs_osi_Wait(ams, event, aintok);
505 afs_osi_Wait(afs_int32 msec, struct afs_osi_WaitHandle *handle, int intok)
511 int glockOwner = ISAFS_GLOCK();
513 tv.tv_sec = msec / 1000;
514 tv.tv_nsec = (msec % 1000) * 1000000;
515 if (handle == NULL) {
519 usr_thread_sleep(&tv);
525 usr_mutex_lock(&osi_waitq_lock);
529 index = WAITHASH((caddr_t) handle);
530 if (osi_waithash_avail == NULL) {
531 waitp = afs_osi_Alloc(sizeof(osi_wait_t));
532 usr_cond_init(&waitp->cond);
534 waitp = osi_waithash_avail;
535 osi_waithash_avail = osi_waithash_avail->next;
537 waitp->addr = (caddr_t) handle;
539 DLL_INSERT_TAIL(waitp, osi_waithash_table[index].head,
540 osi_waithash_table[index].tail, next, prev);
541 tv.tv_sec += time(NULL);
542 waitp->expiration = tv.tv_sec + ((tv.tv_nsec == 0) ? 0 : 1);
543 DLL_INSERT_TAIL(waitp, osi_timedwait_head, osi_timedwait_tail,
544 timedNext, timedPrev);
545 usr_cond_wait(&waitp->cond, &osi_waitq_lock);
551 DLL_DELETE(waitp, osi_waithash_table[index].head,
552 osi_waithash_table[index].tail, next, prev);
553 DLL_DELETE(waitp, osi_timedwait_head, osi_timedwait_tail, timedNext,
555 waitp->next = osi_waithash_avail;
556 osi_waithash_avail = waitp;
557 usr_mutex_unlock(&osi_waitq_lock);
566 afs_osi_CancelWait(struct afs_osi_WaitHandle *handle)
568 afs_osi_Wakeup(handle);
572 * Netscape NSAPI doesn't have a cond_timed_wait, so we need
573 * to explicitly signal cond_timed_waits when their timers expire
576 afs_osi_CheckTimedWaits(void)
581 curTime = time(NULL);
582 usr_mutex_lock(&osi_waitq_lock);
583 waitp = osi_timedwait_head;
584 while (waitp != NULL) {
585 usr_assert(waitp->expiration != 0);
586 if (waitp->expiration <= curTime) {
588 usr_cond_signal(&waitp->cond);
590 waitp = waitp->timedNext;
592 usr_mutex_unlock(&osi_waitq_lock);
597 * 'dummy' vnode, for non-AFS files. We don't actually need most vnode
598 * information for non-AFS files, so point all of them towards this vnode
601 static struct usr_vnode dummy_vnode = {
612 * Allocate a slot in the file table if there is not one there already,
613 * copy in the file name and kludge up the vnode and inode structures
616 lookupname(char *fnamep, int segflg, int followlink,
617 struct usr_vnode **compvpp)
622 * Assume relative pathnames refer to files in AFS
624 if (*fnamep != '/' || uafs_afsPathName(fnamep) != NULL) {
626 code = uafs_LookupName(fnamep, afs_CurrentDir, compvpp, 0, 0);
631 /* For non-afs files, nobody really looks at the meaningful values in the
632 * returned vnode, so we can return a 'fake' one. The vnode can be held,
633 * released, etc. and some callers check for a NULL vnode anyway, so we
634 * to return something. */
636 usr_mutex_lock(&osi_dummy_lock);
637 VN_HOLD(&dummy_vnode);
638 usr_mutex_unlock(&osi_dummy_lock);
640 *compvpp = &dummy_vnode;
646 * open a file given its i-node number
649 osi_UFSOpen(afs_dcache_id_t *ino)
658 fp = afs_osi_Alloc(sizeof(struct osi_file));
659 usr_assert(fp != NULL);
661 usr_assert(ino->ufs);
663 fp->fd = open(ino->ufs, O_RDWR | O_CREAT, 0);
665 get_user_struct()->u_error = errno;
666 afs_osi_Free((char *)fp, sizeof(struct osi_file));
670 rc = fstat(fp->fd, &st);
672 get_user_struct()->u_error = errno;
673 afs_osi_Free((void *)fp, sizeof(struct osi_file));
677 fp->size = st.st_size;
679 fp->vnode = (struct usr_vnode *)fp;
686 osi_UFSClose(struct osi_file *fp)
695 get_user_struct()->u_error = errno;
696 afs_osi_Free((void *)fp, sizeof(struct osi_file));
700 afs_osi_Free((void *)fp, sizeof(struct osi_file));
706 osi_UFSTruncate(struct osi_file *fp, afs_int32 len)
713 rc = ftruncate(fp->fd, len);
715 get_user_struct()->u_error = errno;
725 afs_osi_Read(struct osi_file *fp, int offset, void *buf, afs_int32 len)
734 rc = lseek(fp->fd, offset, SEEK_SET);
736 rc = lseek(fp->fd, fp->offset, SEEK_SET);
739 get_user_struct()->u_error = errno;
744 ret = read(fp->fd, buf, len);
746 get_user_struct()->u_error = errno;
751 rc = fstat(fp->fd, &st);
753 get_user_struct()->u_error = errno;
757 fp->size = st.st_size;
763 afs_osi_Write(struct osi_file *fp, afs_int32 offset, void *buf, afs_int32 len)
772 rc = lseek(fp->fd, offset, SEEK_SET);
774 rc = lseek(fp->fd, fp->offset, SEEK_SET);
777 get_user_struct()->u_error = errno;
782 ret = write(fp->fd, buf, len);
784 get_user_struct()->u_error = errno;
789 rc = fstat(fp->fd, &st);
791 get_user_struct()->u_error = errno;
795 fp->size = st.st_size;
801 afs_osi_Stat(struct osi_file *fp, struct osi_stat *stp)
807 rc = fstat(fp->fd, &st);
809 get_user_struct()->u_error = errno;
813 stp->size = st.st_size;
814 stp->mtime = st.st_mtime;
815 stp->atime = st.st_atime;
824 afs_osi_VOP_RDWR(struct usr_vnode *vnodeP, struct usr_uio *uioP, int rw,
825 int flags, struct usr_ucred *credP)
828 struct osi_file *fp = (struct osi_file *)vnodeP;
831 * We don't support readv/writev.
833 usr_assert(uioP->uio_iovcnt == 1);
834 usr_assert(uioP->uio_resid == uioP->uio_iov[0].iov_len);
836 if (rw == UIO_WRITE) {
837 usr_assert(uioP->uio_fmode == FWRITE);
838 rc = afs_osi_Write(fp, uioP->uio_offset, uioP->uio_iov[0].iov_base,
839 uioP->uio_iov[0].iov_len);
841 usr_assert(uioP->uio_fmode == FREAD);
842 rc = afs_osi_Read(fp, uioP->uio_offset, uioP->uio_iov[0].iov_base,
843 uioP->uio_iov[0].iov_len);
846 return get_user_struct()->u_error;
849 uioP->uio_resid -= rc;
850 uioP->uio_offset += rc;
851 uioP->uio_iov[0].iov_base = (char *)(uioP->uio_iov[0].iov_base) + rc;
852 uioP->uio_iov[0].iov_len -= rc;
857 afs_osi_Alloc(size_t size)
863 afs_osi_Free(void *ptr, size_t size)
869 afs_osi_FreeStr(char *ptr)
875 osi_AllocLargeSpace(size_t size)
877 AFS_STATCNT(osi_AllocLargeSpace);
878 return afs_osi_Alloc(size);
882 osi_FreeLargeSpace(void *ptr)
884 AFS_STATCNT(osi_FreeLargeSpace);
885 afs_osi_Free(ptr, 0);
889 osi_AllocSmallSpace(size_t size)
891 AFS_STATCNT(osi_AllocSmallSpace);
892 return afs_osi_Alloc(size);
896 osi_FreeSmallSpace(void *ptr)
898 AFS_STATCNT(osi_FreeSmallSpace);
899 afs_osi_Free(ptr, 0);
905 AFS_STATCNT(shutdown_osi);
910 shutdown_osinet(void)
912 AFS_STATCNT(shutdown_osinet);
917 shutdown_osifile(void)
919 AFS_STATCNT(shutdown_osifile);
924 afs_nfsclient_init(void)
929 shutdown_nfsclnt(void)
935 afs_osi_Invisible(void)
941 afs_osi_Visible(void)
947 osi_GetTime(struct timeval *tv)
949 gettimeofday(tv, NULL);
954 osi_SetTime(struct timeval *tv)
960 osi_Active(struct vcache *avc)
962 AFS_STATCNT(osi_Active);
969 afs_osi_MapStrategy(int (*aproc) (struct usr_buf *), struct usr_buf *bp)
971 afs_int32 returnCode;
972 returnCode = (*aproc) (bp);
977 osi_FlushPages(struct vcache *avc, afs_ucred_t *credp)
979 ObtainSharedLock(&avc->lock, 555);
980 if ((hcmp((avc->f.m.DataVersion), (avc->mapDV)) <= 0)
981 || ((avc->execsOrWriters > 0) && afs_DirtyPages(avc))) {
982 ReleaseSharedLock(&avc->lock);
985 UpgradeSToWLock(&avc->lock, 565);
986 hset(avc->mapDV, avc->f.m.DataVersion);
987 ReleaseWriteLock(&avc->lock);
992 osi_FlushText_really(struct vcache *vp)
994 if (hcmp(vp->f.m.DataVersion, vp->flushDV) > 0) {
995 hset(vp->flushDV, vp->f.m.DataVersion);
1001 osi_SyncVM(struct vcache *avc)
1007 osi_ReleaseVM(struct vcache *avc, int len, struct usr_ucred *credp)
1019 * Use the thread specific data to implement the user structure
1021 usr_keycreate(&afs_global_u_key, free);
1024 * Initialize the global ucred structure
1026 afs_global_ucredp = (struct usr_ucred *)
1027 afs_osi_Alloc(sizeof(struct usr_ucred));
1028 usr_assert(afs_global_ucredp != NULL);
1029 afs_global_ucredp->cr_ref = 1;
1030 afs_set_cr_uid(afs_global_ucredp, geteuid());
1031 afs_set_cr_gid(afs_global_ucredp, getegid());
1032 afs_set_cr_ruid(afs_global_ucredp, getuid());
1033 afs_set_cr_rgid(afs_global_ucredp, getgid());
1034 afs_global_ucredp->cr_suid = afs_cr_ruid(afs_global_ucredp);
1035 afs_global_ucredp->cr_sgid = afs_cr_rgid(afs_global_ucredp);
1036 st = getgroups(NGROUPS, &afs_global_ucredp->cr_groups[0]);
1037 usr_assert(st >= 0);
1038 afs_global_ucredp->cr_ngroups = (unsigned long)st;
1039 for (i = st; i < NGROUPS; i++) {
1040 afs_global_ucredp->cr_groups[i] = NOGROUP;
1044 * Initialize the global process structure
1046 afs_global_procp = (struct usr_proc *)
1047 afs_osi_Alloc(sizeof(struct usr_proc));
1048 usr_assert(afs_global_procp != NULL);
1049 afs_global_procp->p_pid = osi_getpid();
1050 afs_global_procp->p_ppid = (pid_t) 1;
1051 afs_global_procp->p_ucred = afs_global_ucredp;
1054 * Initialize the mutex and condition variable used to implement
1057 pthread_mutex_init(&usr_sleep_mutex, NULL);
1058 pthread_cond_init(&usr_sleep_cond, NULL);
1061 * Initialize the hash table used for sleep/wakeup
1063 for (i = 0; i < OSI_WAITHASH_SIZE; i++) {
1064 DLL_INIT_LIST(osi_waithash_table[i].head, osi_waithash_table[i].tail);
1066 DLL_INIT_LIST(osi_timedwait_head, osi_timedwait_tail);
1067 osi_waithash_avail = NULL;
1070 * Initialize the AFS file table
1072 for (i = 0; i < MAX_OSI_FILES; i++) {
1073 afs_FileTable[i] = NULL;
1077 * Initialize the global locks
1079 usr_mutex_init(&afs_global_lock);
1080 usr_mutex_init(&rx_global_lock);
1081 usr_mutex_init(&osi_dummy_lock);
1082 usr_mutex_init(&osi_waitq_lock);
1083 usr_mutex_init(&osi_authenticate_lock);
1086 * Initialize the AFS OSI credentials
1088 afs_osi_cred = *afs_global_ucredp;
1089 afs_osi_credp = &afs_osi_cred;
1091 init_et_to_sys_error();
1095 * Set the UDP port number RX uses for UDP datagrams
1098 uafs_SetRxPort(int port)
1100 usr_assert(usr_rx_port == 0);
1105 * uafs_Init is for backwards compatibility only! Do not use it; use
1106 * uafs_Setup, uafs_ParseArgs, and uafs_Run instead.
1109 uafs_Init(char *rn, char *mountDirParam, char *confDirParam,
1110 char *cacheBaseDirParam, int cacheBlocksParam, int cacheFilesParam,
1111 int cacheStatEntriesParam, int dCacheSizeParam, int vCacheSizeParam,
1112 int chunkSizeParam, int closeSynchParam, int debugParam,
1113 int nDaemonsParam, int cacheFlagsParam, char *logFile)
1123 code = uafs_Setup(mountDirParam);
1124 usr_assert(code == 0);
1127 if (mountDirParam) {
1128 argv[argc++] = "-mountdir";
1129 argv[argc++] = mountDirParam;
1132 argv[argc++] = "-confdir";
1133 argv[argc++] = confDirParam;
1135 if (cacheBaseDirParam) {
1136 argv[argc++] = "-cachedir";
1137 argv[argc++] = cacheBaseDirParam;
1139 if (cacheBlocksParam) {
1140 snprintf(buf, sizeof(buf), "%d", cacheBlocksParam);
1142 argv[argc++] = "-blocks";
1143 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1145 if (cacheFilesParam) {
1146 snprintf(buf, sizeof(buf), "%d", cacheFilesParam);
1148 argv[argc++] = "-files";
1149 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1151 if (cacheStatEntriesParam) {
1152 snprintf(buf, sizeof(buf), "%d", cacheStatEntriesParam);
1154 argv[argc++] = "-stat";
1155 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1157 if (dCacheSizeParam) {
1158 snprintf(buf, sizeof(buf), "%d", dCacheSizeParam);
1160 argv[argc++] = "-dcache";
1161 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1163 if (vCacheSizeParam) {
1164 snprintf(buf, sizeof(buf), "%d", vCacheSizeParam);
1166 argv[argc++] = "-volumes";
1167 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1169 if (chunkSizeParam) {
1170 snprintf(buf, sizeof(buf), "%d", chunkSizeParam);
1172 argv[argc++] = "-chunksize";
1173 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1175 if (closeSynchParam) {
1176 argv[argc++] = "-waitclose";
1179 argv[argc++] = "-debug";
1181 if (nDaemonsParam) {
1182 snprintf(buf, sizeof(buf), "%d", nDaemonsParam);
1184 argv[argc++] = "-daemons";
1185 argv[argc++] = freeargv[freeargc++] = strdup(buf);
1187 if (cacheFlagsParam) {
1188 if (cacheFlagsParam & AFSCALL_INIT_MEMCACHE) {
1189 argv[argc++] = "-memcache";
1193 argv[argc++] = "-logfile";
1194 argv[argc++] = logFile;
1199 code = uafs_ParseArgs(argc, argv);
1200 usr_assert(code == 0);
1202 for (i = 0; i < freeargc; i++) {
1207 usr_assert(code == 0);
1211 * Calculate the cacheMountDir used for a specified dir.
1213 * @param[in] dir Desired mount dir
1214 * @param[out] mountdir On success, contains the literal string that should
1215 * be used as the cache mount dir.
1216 * @param[in] size The number of bytes allocated in mountdir
1218 * @post On success, mountdir begins with a slash, and does not contain two
1219 * slashes adjacent to each other
1221 * @return operation status
1223 * @retval ENAMETOOLONG the specified dir is too long to fix in the given
1225 * @retval EINVAL the specified dir does not actually specify any meaningful
1229 calcMountDir(const char *dir, char *mountdir, size_t size)
1236 if (dir && strlen(dir) > size-1) {
1237 return ENAMETOOLONG;
1241 * Initialize the AFS mount point, default is '/afs'.
1242 * Strip duplicate/trailing slashes from mount point string.
1243 * afs_mountDirLen is set to strlen(afs_mountDir).
1248 sprintf(buf, "%s", dir);
1252 for (lastchar = '/', p = &buf[0]; *p != '\0'; p++) {
1253 if (lastchar != '/' || *p != '/') {
1254 mountdir[len++] = lastchar = *p;
1257 if (lastchar == '/' && len > 1)
1259 mountdir[len] = '\0';
1272 * Mount the AFS filesystem
1275 rc = afs_mount(&afs_RootVfs, NULL, NULL);
1276 usr_assert(rc == 0);
1277 rc = afs_root(&afs_RootVfs, &afs_RootVnode);
1278 usr_assert(rc == 0);
1282 * initialize the current directory to the AFS root
1284 afs_CurrentDir = afs_RootVnode;
1285 VN_HOLD(afs_CurrentDir);
1291 uafs_setMountDir(const char *dir)
1295 char tmp_mountDir[1024];
1297 rc = calcMountDir(dir, tmp_mountDir, sizeof(tmp_mountDir));
1299 afs_warn("Invalid mount dir specification (error %d): %s\n", rc, dir);
1301 if (strcmp(tmp_mountDir, afs_mountDir) != 0) {
1302 /* mount dir changed */
1303 strcpy(afs_mountDir, tmp_mountDir);
1304 afs_mountDirLen = strlen(afs_mountDir);
1311 uafs_statvfs(struct statvfs *buf)
1317 rc = afs_statvfs(&afs_RootVfs, buf);
1337 if (afs_CurrentDir) {
1338 VN_RELE(afs_CurrentDir);
1340 rc = afs_unmount(&afs_RootVfs);
1341 usr_assert(rc == 0);
1348 * Donate the current thread to the RX server pool.
1351 uafs_RxServerProc(void)
1355 struct rx_call *newcall = NULL;
1357 rxi_MorePackets(2); /* alloc more packets */
1358 threadID = rxi_availProcs++;
1361 sock = OSI_NULLSOCKET;
1362 rxi_ServerProc(threadID, newcall, &sock);
1363 if (sock == OSI_NULLSOCKET) {
1368 rxi_ListenerProc(sock, &threadID, &newcall);
1369 /* assert(threadID != -1); */
1370 /* assert(newcall != NULL); */
1374 struct syscallThreadArgs {
1384 syscallThread(void *argp)
1387 struct usr_ucred *crp;
1388 struct syscallThreadArgs *sysArgsP = (struct syscallThreadArgs *)argp;
1391 * AFS daemons run authenticated
1393 get_user_struct()->u_viceid = getuid();
1394 crp = get_user_struct()->u_cred;
1395 afs_set_cr_uid(crp, getuid());
1396 afs_set_cr_ruid(crp, getuid());
1397 crp->cr_suid = getuid();
1398 crp->cr_groups[0] = getgid();
1399 crp->cr_ngroups = 1;
1400 for (i = 1; i < NGROUPS; i++) {
1401 crp->cr_groups[i] = NOGROUP;
1404 call_syscall(sysArgsP->syscall, sysArgsP->afscall, sysArgsP->param1,
1405 sysArgsP->param2, sysArgsP->param3, sysArgsP->param4);
1407 afs_osi_Free(argp, -1);
1412 fork_syscall(long syscall, long afscall, long param1, long param2,
1413 long param3, long param4)
1416 struct syscallThreadArgs *sysArgsP;
1418 sysArgsP = (struct syscallThreadArgs *)
1419 afs_osi_Alloc(sizeof(struct syscallThreadArgs));
1420 usr_assert(sysArgsP != NULL);
1421 sysArgsP->syscall = syscall;
1422 sysArgsP->afscall = afscall;
1423 sysArgsP->param1 = param1;
1424 sysArgsP->param2 = param2;
1425 sysArgsP->param3 = param3;
1426 sysArgsP->param4 = param4;
1428 usr_thread_create(&tid, syscallThread, sysArgsP);
1429 usr_thread_detach(tid);
1434 call_syscall(long syscall, long afscall, long param1, long param2,
1435 long param3, long param4)
1447 a.syscall = syscall;
1448 a.afscall = afscall;
1454 get_user_struct()->u_error = 0;
1455 get_user_struct()->u_ap = (char *)&a;
1457 code = Afs_syscall();
1462 uafs_Setup(const char *mount)
1465 static int inited = 0;
1472 rc = calcMountDir(mount, afs_mountDir, sizeof(afs_mountDir));
1476 afs_mountDirLen = strlen(afs_mountDir);
1478 /* initialize global vars and such */
1481 /* initialize cache manager foo */
1488 uafs_ParseArgs(int argc, char **argv)
1490 return afsd_parse(argc, argv);
1502 return afsd_cacheMountDir;
1506 uafs_SetTokens(char *tbuffer, int tlen)
1509 struct afs_ioctl iob;
1514 iob.out = &outbuf[0];
1515 iob.out_size = sizeof(outbuf);
1517 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(3), (long)&iob, 0, 0);
1526 uafs_RPCStatsEnableProc(void)
1529 struct afs_ioctl iob;
1532 flag = AFSCALL_RXSTATS_ENABLE;
1533 iob.in = (char *)&flag;
1534 iob.in_size = sizeof(afs_int32);
1537 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1546 uafs_RPCStatsDisableProc(void)
1549 struct afs_ioctl iob;
1552 flag = AFSCALL_RXSTATS_DISABLE;
1553 iob.in = (char *)&flag;
1554 iob.in_size = sizeof(afs_int32);
1557 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1566 uafs_RPCStatsClearProc(void)
1569 struct afs_ioctl iob;
1572 flag = AFSCALL_RXSTATS_CLEAR;
1573 iob.in = (char *)&flag;
1574 iob.in_size = sizeof(afs_int32);
1577 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(53), (long)&iob, 0, 0);
1586 uafs_RPCStatsEnablePeer(void)
1589 struct afs_ioctl iob;
1592 flag = AFSCALL_RXSTATS_ENABLE;
1593 iob.in = (char *)&flag;
1594 iob.in_size = sizeof(afs_int32);
1597 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1606 uafs_RPCStatsDisablePeer(void)
1609 struct afs_ioctl iob;
1612 flag = AFSCALL_RXSTATS_DISABLE;
1613 iob.in = (char *)&flag;
1614 iob.in_size = sizeof(afs_int32);
1617 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1626 uafs_RPCStatsClearPeer(void)
1629 struct afs_ioctl iob;
1632 flag = AFSCALL_RXSTATS_CLEAR;
1633 iob.in = (char *)&flag;
1634 iob.in_size = sizeof(afs_int32);
1637 rc = call_syscall(AFSCALL_PIOCTL, 0, _VICEIOCTL(54), (long)&iob, 0, 0);
1646 * Lookup the target of a symbolic link
1647 * Call VN_HOLD on the output vnode if successful.
1648 * Returns zero on success, error code on failure.
1649 * If provided, use a path for confirming we are not linked to ourself.
1651 * Note: Caller must hold the AFS global lock.
1654 uafs_LookupLinkPath(struct usr_vnode *vp, struct usr_vnode *parentVp,
1655 char *ppathP, struct usr_vnode **vpp)
1660 struct usr_vnode *linkVp;
1662 struct iovec iov[1];
1666 pathP = afs_osi_Alloc(MAX_OSI_PATH + 1);
1667 usr_assert(pathP != NULL);
1670 * set up the uio buffer
1672 iov[0].iov_base = pathP;
1673 iov[0].iov_len = MAX_OSI_PATH + 1;
1674 uio.uio_iov = &iov[0];
1678 uio.uio_fmode = FREAD;
1679 uio.uio_resid = MAX_OSI_PATH + 1;
1682 * Read the link data
1684 code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
1686 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1689 len = MAX_OSI_PATH + 1 - uio.uio_resid;
1692 /* are we linked to ourname or ./ourname? ELOOP */
1694 if ((strcmp(pathP, ppathP) == 0) ||
1695 ((pathP[0] == '.') &&
1696 (pathP[1] == '/') &&
1697 (strcmp(&(pathP[2]), ppathP) == 0))) {
1703 * Find the target of the symbolic link
1705 code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0);
1707 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1711 afs_osi_Free(pathP, MAX_OSI_PATH + 1);
1717 * Lookup a file or directory given its path.
1718 * Call VN_HOLD on the output vnode if successful.
1719 * Returns zero on success, error code on failure.
1721 * Note: Caller must hold the AFS global lock.
1724 uafs_LookupName(char *path, struct usr_vnode *parentVp,
1725 struct usr_vnode **vpp, int follow, int no_eval_mtpt)
1729 struct usr_vnode *vp;
1730 struct usr_vnode *nextVp;
1731 struct usr_vnode *linkVp;
1732 struct vcache *nextVc;
1735 char *nextPathP = NULL;
1740 * Absolute paths must start with the AFS mount point.
1742 if (path[0] != '/') {
1745 path = uafs_afsPathName(path);
1753 * Loop through the path looking for the new directory
1755 tmpPath = afs_osi_Alloc(strlen(path) + 1);
1756 usr_assert(tmpPath != NULL);
1757 strcpy(tmpPath, path);
1760 while (pathP != NULL && *pathP != '\0') {
1761 usr_assert(*pathP != '/');
1764 * terminate the current component and skip over slashes
1766 nextPathP = afs_strchr(pathP, '/');
1767 if (nextPathP != NULL) {
1768 while (*nextPathP == '/') {
1769 *(nextPathP++) = '\0';
1774 * Don't call afs_lookup on non-directories
1776 if (vp->v_type != VDIR) {
1778 afs_osi_Free(tmpPath, strlen(path) + 1);
1782 if (vp == afs_RootVnode && strcmp(pathP, "..") == 0) {
1784 * The AFS root is its own parent
1786 nextVp = afs_RootVnode;
1789 * We need execute permission to search a directory
1791 code = afs_access(VTOAFS(vp), VEXEC, get_user_struct()->u_cred);
1794 afs_osi_Free(tmpPath, strlen(path) + 1);
1799 * lookup the next component in the path, we can release the
1800 * subdirectory since we hold the global lock
1804 if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt)
1805 code = afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred, 0);
1808 afs_lookup(VTOAFS(vp), pathP, &nextVc, get_user_struct()->u_cred,
1811 nextVp=AFSTOV(nextVc);
1814 afs_osi_Free(tmpPath, strlen(path) + 1);
1820 * Follow symbolic links for parent directories and
1821 * for leaves when the follow flag is set.
1823 if ((nextPathP != NULL && *nextPathP != '\0') || follow) {
1825 while (nextVp->v_type == VLNK) {
1826 if (++linkCount > MAX_OSI_LINKS) {
1829 afs_osi_Free(tmpPath, strlen(path) + 1);
1832 code = uafs_LookupLinkPath(nextVp, vp, NULL, &linkVp);
1836 afs_osi_Free(tmpPath, strlen(path) + 1);
1850 * Special case, nextPathP is non-null if pathname ends in slash
1852 if (nextPathP != NULL && vp->v_type != VDIR) {
1854 afs_osi_Free(tmpPath, strlen(path) + 1);
1858 afs_osi_Free(tmpPath, strlen(path) + 1);
1864 uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentVp,
1865 struct usr_vnode **vpp)
1867 return uafs_LookupLinkPath(vp, parentVp, NULL, vpp);
1871 * Lookup the parent of a file or directory given its path
1872 * Call VN_HOLD on the output vnode if successful.
1873 * Returns zero on success, error code on failure.
1875 * Note: Caller must hold the AFS global lock.
1878 uafs_LookupParent(char *path, struct usr_vnode **vpp)
1883 struct usr_vnode *parentP;
1888 * Absolute path names must start with the AFS mount point.
1891 pathP = uafs_afsPathName(path);
1892 if (pathP == NULL) {
1898 * Find the length of the parent path
1901 while (len > 0 && path[len - 1] == '/') {
1907 while (len > 0 && path[len - 1] != '/') {
1914 pathP = afs_osi_Alloc(len);
1915 usr_assert(pathP != NULL);
1916 memcpy(pathP, path, len - 1);
1917 pathP[len - 1] = '\0';
1920 * look up the parent
1922 code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0);
1923 afs_osi_Free(pathP, len);
1927 if (parentP->v_type != VDIR) {
1937 * Return a pointer to the first character in the last component
1941 uafs_LastPath(char *path)
1946 while (len > 0 && path[len - 1] == '/') {
1949 while (len > 0 && path[len - 1] != '/') {
1959 * Set the working directory.
1962 uafs_chdir(char *path)
1966 retval = uafs_chdir_r(path);
1972 uafs_chdir_r(char *path)
1977 code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0);
1982 if (dirP->v_type != VDIR) {
1987 VN_RELE(afs_CurrentDir);
1988 afs_CurrentDir = dirP;
1993 * Create a directory.
1996 uafs_mkdir(char *path, int mode)
2000 retval = uafs_mkdir_r(path, mode);
2006 uafs_mkdir_r(char *path, int mode)
2010 struct vnode *parentP;
2011 struct vcache *dirP;
2012 struct usr_vattr attrs;
2014 if (uafs_IsRoot(path)) {
2019 * Look up the parent directory.
2021 nameP = uafs_LastPath(path);
2022 if (nameP != NULL) {
2023 code = uafs_LookupParent(path, &parentP);
2029 parentP = afs_CurrentDir;
2035 * Make sure the directory has at least one character
2037 if (*nameP == '\0') {
2044 * Create the directory
2046 usr_vattr_null(&attrs);
2047 attrs.va_type = VREG;
2048 attrs.va_mode = mode;
2049 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2050 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2052 code = afs_mkdir(VTOAFS(parentP), nameP, &attrs, &dirP, get_user_struct()->u_cred);
2058 VN_RELE(AFSTOV(dirP));
2063 * Return 1 if path is the AFS root, otherwise return 0
2066 uafs_IsRoot(char *path)
2068 while (*path == '/' && *(path + 1) == '/') {
2071 if (strncmp(path, afs_mountDir, afs_mountDirLen) != 0) {
2074 path += afs_mountDirLen;
2075 while (*path == '/') {
2078 if (*path != '\0') {
2086 * Note: file name may not end in a slash.
2089 uafs_open(char *path, int flags, int mode)
2093 retval = uafs_open_r(path, flags, mode);
2099 uafs_open_r(char *path, int flags, int mode)
2105 struct usr_vnode *fileP;
2106 struct usr_vnode *dirP;
2107 struct usr_vattr attrs;
2112 if (uafs_IsRoot(path)) {
2113 fileP = afs_RootVnode;
2117 * Look up the parent directory.
2119 nameP = uafs_LastPath(path);
2120 if (nameP != NULL) {
2121 code = uafs_LookupParent(path, &dirP);
2127 dirP = afs_CurrentDir;
2133 * Make sure the filename has at least one character
2135 if (*nameP == '\0') {
2142 * Get the VNODE for this file
2144 if (flags & O_CREAT) {
2145 usr_vattr_null(&attrs);
2146 attrs.va_type = VREG;
2147 attrs.va_mode = mode;
2148 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
2149 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
2150 if (flags & O_TRUNC) {
2156 afs_create(VTOAFS(dirP), nameP, &attrs,
2157 (flags & O_EXCL) ? usr_EXCL : usr_NONEXCL, mode,
2158 &vc, get_user_struct()->u_cred);
2167 code = uafs_LookupName(nameP, dirP, &fileP, 1, 0);
2175 * Check whether we have access to this file
2178 if (flags & (O_RDONLY | O_RDWR)) {
2181 if (flags & (O_WRONLY | O_RDWR)) {
2185 fileMode = VREAD; /* since O_RDONLY is 0 */
2186 code = afs_access(VTOAFS(fileP), fileMode, get_user_struct()->u_cred);
2194 * Get the file attributes, all we need is the size
2196 code = afs_getattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2206 * Setup the open flags
2209 if (flags & O_TRUNC) {
2210 openFlags |= FTRUNC;
2212 if (flags & O_APPEND) {
2213 openFlags |= FAPPEND;
2215 if (flags & O_SYNC) {
2218 if (flags & O_SYNC) {
2221 if (flags & (O_RDONLY | O_RDWR)) {
2224 if (flags & (O_WRONLY | O_RDWR)) {
2225 openFlags |= FWRITE;
2227 if ((openFlags & (FREAD | FWRITE)) == 0) {
2228 /* O_RDONLY is 0, so ... */
2233 * Truncate if necessary
2235 if ((flags & O_TRUNC) && (attrs.va_size != 0)) {
2236 usr_vattr_null(&attrs);
2237 attrs.va_mask = ATTR_SIZE;
2239 code = afs_setattr(VTOAFS(fileP), &attrs, get_user_struct()->u_cred);
2251 code = afs_open(&vc, openFlags, get_user_struct()->u_cred);
2259 * Put the vnode pointer into the file table
2261 for (fd = 0; fd < MAX_OSI_FILES; fd++) {
2262 if (afs_FileTable[fd] == NULL) {
2263 afs_FileTable[fd] = fileP;
2264 afs_FileFlags[fd] = openFlags;
2265 if (flags & O_APPEND) {
2266 afs_FileOffsets[fd] = attrs.va_size;
2268 afs_FileOffsets[fd] = 0;
2273 if (fd == MAX_OSI_FILES) {
2286 uafs_creat(char *path, int mode)
2289 rc = uafs_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2294 uafs_creat_r(char *path, int mode)
2297 rc = uafs_open_r(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
2305 uafs_write(int fd, char *buf, int len)
2309 retval = uafs_pwrite_r(fd, buf, len, afs_FileOffsets[fd]);
2315 uafs_pwrite(int fd, char *buf, int len, off_t offset)
2319 retval = uafs_pwrite_r(fd, buf, len, offset);
2325 uafs_pwrite_r(int fd, char *buf, int len, off_t offset)
2329 struct iovec iov[1];
2330 struct usr_vnode *fileP;
2333 * Make sure this is an open file
2335 fileP = afs_FileTable[fd];
2336 if (fileP == NULL) {
2342 * set up the uio buffer
2344 iov[0].iov_base = buf;
2345 iov[0].iov_len = len;
2346 uio.uio_iov = &iov[0];
2348 uio.uio_offset = offset;
2350 uio.uio_fmode = FWRITE;
2351 uio.uio_resid = len;
2357 code = afs_write(VTOAFS(fileP), &uio, afs_FileFlags[fd], get_user_struct()->u_cred, 0);
2363 afs_FileOffsets[fd] = uio.uio_offset;
2364 return (len - uio.uio_resid);
2371 uafs_read(int fd, char *buf, int len)
2375 retval = uafs_pread_r(fd, buf, len, afs_FileOffsets[fd]);
2381 uafs_pread_nocache(int fd, char *buf, int len, off_t offset)
2385 retval = uafs_pread_nocache_r(fd, buf, len, offset);
2391 uafs_pread_nocache_r(int fd, char *buf, int len, off_t offset)
2394 struct iovec iov[1];
2395 struct usr_vnode *fileP;
2396 struct nocache_read_request *bparms;
2400 * Make sure this is an open file
2402 fileP = afs_FileTable[fd];
2403 if (fileP == NULL) {
2408 /* these get freed in PrefetchNoCache, so... */
2409 bparms = afs_osi_Alloc(sizeof(struct nocache_read_request));
2410 bparms->areq = afs_osi_Alloc(sizeof(struct vrequest));
2412 code = afs_InitReq(bparms->areq, get_user_struct()->u_cred);
2414 afs_osi_Free(bparms->areq, sizeof(struct vrequest));
2415 afs_osi_Free(bparms, sizeof(struct nocache_read_request));
2420 bparms->auio = &uio;
2421 bparms->offset = offset;
2422 bparms->length = len;
2425 * set up the uio buffer
2427 iov[0].iov_base = buf;
2428 iov[0].iov_len = len;
2429 uio.uio_iov = &iov[0];
2431 uio.uio_offset = offset;
2433 uio.uio_fmode = FREAD;
2434 uio.uio_resid = len;
2439 code = afs_PrefetchNoCache(VTOAFS(fileP), get_user_struct()->u_cred,
2447 afs_FileOffsets[fd] = uio.uio_offset;
2448 return (len - uio.uio_resid);
2452 uafs_pread(int fd, char *buf, int len, off_t offset)
2456 retval = uafs_pread_r(fd, buf, len, offset);
2462 uafs_pread_r(int fd, char *buf, int len, off_t offset)
2466 struct iovec iov[1];
2467 struct usr_vnode *fileP;
2470 * Make sure this is an open file
2472 fileP = afs_FileTable[fd];
2473 if (fileP == NULL) {
2479 * set up the uio buffer
2481 iov[0].iov_base = buf;
2482 iov[0].iov_len = len;
2483 uio.uio_iov = &iov[0];
2485 uio.uio_offset = offset;
2487 uio.uio_fmode = FREAD;
2488 uio.uio_resid = len;
2493 code = afs_read(VTOAFS(fileP), &uio, get_user_struct()->u_cred, 0);
2499 afs_FileOffsets[fd] = uio.uio_offset;
2500 return (len - uio.uio_resid);
2504 * Copy the attributes of a file into a stat structure.
2506 * NOTE: Caller must hold the global AFS lock.
2509 uafs_GetAttr(struct usr_vnode *vp, struct stat *stats)
2512 struct usr_vattr attrs;
2517 * Get the attributes
2519 code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2525 * Copy the attributes, zero fields that aren't set
2527 memset((void *)stats, 0, sizeof(struct stat));
2529 stats->st_ino = attrs.va_nodeid;
2530 stats->st_mode = attrs.va_mode;
2531 stats->st_nlink = attrs.va_nlink;
2532 stats->st_uid = attrs.va_uid;
2533 stats->st_gid = attrs.va_gid;
2534 stats->st_rdev = attrs.va_rdev;
2535 stats->st_size = attrs.va_size;
2536 stats->st_atime = attrs.va_atime.tv_sec;
2537 stats->st_mtime = attrs.va_mtime.tv_sec;
2538 stats->st_ctime = attrs.va_ctime.tv_sec;
2539 /* preserve dv if possible */
2540 #if defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
2541 stats->st_atimespec.tv_nsec = attrs.va_atime.tv_usec * 1000;
2542 stats->st_mtimespec.tv_nsec = attrs.va_mtime.tv_usec * 1000;
2543 stats->st_ctimespec.tv_nsec = attrs.va_ctime.tv_usec * 1000;
2544 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
2545 stats->st_atimensec = attrs.va_atime.tv_usec * 1000;
2546 stats->st_mtimensec = attrs.va_mtime.tv_usec * 1000;
2547 stats->st_ctimensec = attrs.va_ctime.tv_usec * 1000;
2549 stats->st_blksize = attrs.va_blocksize;
2550 stats->st_blocks = attrs.va_blocks;
2556 * Get the attributes of a file, do follow links
2559 uafs_stat(char *path, struct stat *buf)
2563 retval = uafs_stat_r(path, buf);
2569 uafs_stat_r(char *path, struct stat *buf)
2574 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2579 code = uafs_GetAttr(vp, buf);
2589 * Get the attributes of a file, don't follow links
2592 uafs_lstat(char *path, struct stat *buf)
2596 retval = uafs_lstat_r(path, buf);
2602 uafs_lstat_r(char *path, struct stat *buf)
2607 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
2612 code = uafs_GetAttr(vp, buf);
2622 * Get the attributes of an open file
2625 uafs_fstat(int fd, struct stat *buf)
2629 retval = uafs_fstat_r(fd, buf);
2635 uafs_fstat_r(int fd, struct stat *buf)
2640 vp = afs_FileTable[fd];
2645 code = uafs_GetAttr(vp, buf);
2654 * change the permissions on a file
2657 uafs_chmod(char *path, int mode)
2661 retval = uafs_chmod_r(path, mode);
2667 uafs_chmod_r(char *path, int mode)
2671 struct usr_vattr attrs;
2673 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2678 usr_vattr_null(&attrs);
2679 attrs.va_mask = ATTR_MODE;
2680 attrs.va_mode = mode;
2681 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2691 * change the permissions on an open file
2694 uafs_fchmod(int fd, int mode)
2698 retval = uafs_fchmod_r(fd, mode);
2704 uafs_fchmod_r(int fd, int mode)
2708 struct usr_vattr attrs;
2710 vp = afs_FileTable[fd];
2715 usr_vattr_null(&attrs);
2716 attrs.va_mask = ATTR_MODE;
2717 attrs.va_mode = mode;
2718 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2730 uafs_truncate(char *path, int length)
2734 retval = uafs_truncate_r(path, length);
2740 uafs_truncate_r(char *path, int length)
2744 struct usr_vattr attrs;
2746 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
2751 usr_vattr_null(&attrs);
2752 attrs.va_mask = ATTR_SIZE;
2753 attrs.va_size = length;
2754 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2764 * truncate an open file
2767 uafs_ftruncate(int fd, int length)
2771 retval = uafs_ftruncate_r(fd, length);
2777 uafs_ftruncate_r(int fd, int length)
2781 struct usr_vattr attrs;
2783 vp = afs_FileTable[fd];
2788 usr_vattr_null(&attrs);
2789 attrs.va_mask = ATTR_SIZE;
2790 attrs.va_size = length;
2791 code = afs_setattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2800 * set the read/write file pointer of an open file
2803 uafs_lseek(int fd, int offset, int whence)
2807 retval = uafs_lseek_r(fd, offset, whence);
2813 uafs_lseek_r(int fd, int offset, int whence)
2817 struct usr_vattr attrs;
2818 struct usr_vnode *vp;
2820 vp = afs_FileTable[fd];
2827 newpos = afs_FileOffsets[fd] + offset;
2833 code = afs_getattr(VTOAFS(vp), &attrs, get_user_struct()->u_cred);
2838 newpos = attrs.va_size + offset;
2848 afs_FileOffsets[fd] = newpos;
2860 retval = uafs_fsync_r(fd);
2866 uafs_fsync_r(int fd)
2869 struct usr_vnode *fileP;
2872 fileP = afs_FileTable[fd];
2873 if (fileP == NULL) {
2878 code = afs_fsync(VTOAFS(fileP), get_user_struct()->u_cred);
2895 retval = uafs_close_r(fd);
2901 uafs_close_r(int fd)
2904 struct usr_vnode *fileP;
2906 fileP = afs_FileTable[fd];
2907 if (fileP == NULL) {
2911 afs_FileTable[fd] = NULL;
2913 code = afs_close(VTOAFS(fileP), afs_FileFlags[fd], get_user_struct()->u_cred);
2924 * Create a hard link from the source to the target
2925 * Note: file names may not end in a slash.
2928 uafs_link(char *existing, char *new)
2932 retval = uafs_link_r(existing, new);
2938 uafs_link_r(char *existing, char *new)
2941 struct usr_vnode *existP;
2942 struct usr_vnode *dirP;
2945 if (uafs_IsRoot(new)) {
2950 * Look up the existing node.
2952 code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0);
2959 * Look up the parent directory.
2961 nameP = uafs_LastPath(new);
2962 if (nameP != NULL) {
2963 code = uafs_LookupParent(new, &dirP);
2970 dirP = afs_CurrentDir;
2976 * Make sure the filename has at least one character
2978 if (*nameP == '\0') {
2988 code = afs_link(VTOAFS(existP), VTOAFS(dirP), nameP, get_user_struct()->u_cred);
2999 * Create a symbolic link from the source to the target
3000 * Note: file names may not end in a slash.
3003 uafs_symlink(char *target, char *source)
3007 retval = uafs_symlink_r(target, source);
3013 uafs_symlink_r(char *target, char *source)
3016 struct usr_vnode *dirP;
3017 struct usr_vattr attrs;
3020 if (uafs_IsRoot(source)) {
3025 * Look up the parent directory.
3027 nameP = uafs_LastPath(source);
3028 if (nameP != NULL) {
3029 code = uafs_LookupParent(source, &dirP);
3035 dirP = afs_CurrentDir;
3041 * Make sure the filename has at least one character
3043 if (*nameP == '\0') {
3052 usr_vattr_null(&attrs);
3053 attrs.va_type = VLNK;
3054 attrs.va_mode = 0777;
3055 attrs.va_uid = afs_cr_uid(get_user_struct()->u_cred);
3056 attrs.va_gid = afs_cr_gid(get_user_struct()->u_cred);
3057 code = afs_symlink(VTOAFS(dirP), nameP, &attrs, target, NULL,
3058 get_user_struct()->u_cred);
3068 * Read a symbolic link into the buffer
3071 uafs_readlink(char *path, char *buf, int len)
3075 retval = uafs_readlink_r(path, buf, len);
3081 uafs_readlink_r(char *path, char *buf, int len)
3084 struct usr_vnode *vp;
3086 struct iovec iov[1];
3088 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0);
3094 if (vp->v_type != VLNK) {
3101 * set up the uio buffer
3103 iov[0].iov_base = buf;
3104 iov[0].iov_len = len;
3105 uio.uio_iov = &iov[0];
3109 uio.uio_fmode = FREAD;
3110 uio.uio_resid = len;
3115 code = afs_readlink(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3123 * return the number of bytes read
3125 return (len - uio.uio_resid);
3129 * Remove a file (or directory)
3130 * Note: file name may not end in a slash.
3133 uafs_unlink(char *path)
3137 retval = uafs_unlink_r(path);
3143 uafs_unlink_r(char *path)
3146 struct usr_vnode *dirP;
3149 if (uafs_IsRoot(path)) {
3154 * Look up the parent directory.
3156 nameP = uafs_LastPath(path);
3157 if (nameP != NULL) {
3158 code = uafs_LookupParent(path, &dirP);
3164 dirP = afs_CurrentDir;
3170 * Make sure the filename has at least one character
3172 if (*nameP == '\0') {
3181 code = afs_remove(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3192 * Rename a file (or directory)
3195 uafs_rename(char *old, char *new)
3199 retval = uafs_rename_r(old, new);
3205 uafs_rename_r(char *old, char *new)
3210 struct usr_vnode *odirP;
3211 struct usr_vnode *ndirP;
3213 if (uafs_IsRoot(new)) {
3218 * Look up the parent directories.
3220 onameP = uafs_LastPath(old);
3221 if (onameP != NULL) {
3222 code = uafs_LookupParent(old, &odirP);
3228 odirP = afs_CurrentDir;
3232 nnameP = uafs_LastPath(new);
3233 if (nnameP != NULL) {
3234 code = uafs_LookupParent(new, &ndirP);
3240 ndirP = afs_CurrentDir;
3246 * Make sure the filename has at least one character
3248 if (*onameP == '\0' || *nnameP == '\0') {
3258 code = afs_rename(VTOAFS(odirP), onameP, VTOAFS(ndirP), nnameP, get_user_struct()->u_cred);
3270 * Remove a or directory
3271 * Note: file name may not end in a slash.
3274 uafs_rmdir(char *path)
3278 retval = uafs_rmdir_r(path);
3284 uafs_rmdir_r(char *path)
3287 struct usr_vnode *dirP;
3290 if (uafs_IsRoot(path)) {
3295 * Look up the parent directory.
3297 nameP = uafs_LastPath(path);
3298 if (nameP != NULL) {
3299 code = uafs_LookupParent(path, &dirP);
3305 dirP = afs_CurrentDir;
3311 * Make sure the directory name has at least one character
3313 if (*nameP == '\0') {
3320 * Remove the directory
3322 code = afs_rmdir(VTOAFS(dirP), nameP, get_user_struct()->u_cred);
3333 * Flush a file from the AFS cache
3336 uafs_FlushFile(char *path)
3339 struct afs_ioctl iob;
3347 call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(6), (long)&iob, 0,
3358 uafs_FlushFile_r(char *path)
3362 retval = uafs_FlushFile(path);
3371 uafs_opendir(char *path)
3375 retval = uafs_opendir_r(path);
3381 uafs_opendir_r(char *path)
3384 struct usr_vnode *fileP;
3388 * Open the directory for reading
3390 fd = uafs_open_r(path, O_RDONLY, 0);
3395 fileP = afs_FileTable[fd];
3396 if (fileP == NULL) {
3400 if (fileP->v_type != VDIR) {
3407 * Set up the directory structures
3409 dirp = afs_osi_Alloc(sizeof(usr_DIR) + USR_DIRSIZE +
3410 sizeof(struct usr_dirent));
3411 usr_assert(dirp != NULL);
3412 dirp->dd_buf = (char *)(dirp + 1);
3422 * Read directory entries into a file system independent format.
3423 * This routine was developed to support AFS cache consistency testing.
3424 * You should use uafs_readdir instead.
3427 uafs_getdents(int fd, struct min_direct *buf, int len)
3431 retval = uafs_getdents_r(fd, buf, len);
3437 uafs_getdents_r(int fd, struct min_direct *buf, int len)
3441 struct usr_vnode *vp;
3442 struct iovec iov[1];
3445 * Make sure this is an open file
3447 vp = afs_FileTable[fd];
3455 * set up the uio buffer
3457 iov[0].iov_base = (char *)buf;
3458 iov[0].iov_len = len;
3459 uio.uio_iov = &iov[0];
3461 uio.uio_offset = afs_FileOffsets[fd];
3463 uio.uio_fmode = FREAD;
3464 uio.uio_resid = len;
3467 * read the next chunk from the directory
3469 code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3475 afs_FileOffsets[fd] = uio.uio_offset;
3476 return (len - uio.uio_resid);
3480 * read from a directory (names only)
3483 uafs_readdir(usr_DIR * dirp)
3485 struct usr_dirent *retval;
3487 retval = uafs_readdir_r(dirp);
3493 uafs_readdir_r(usr_DIR * dirp)
3498 struct usr_vnode *vp;
3499 struct iovec iov[1];
3500 struct usr_dirent *direntP;
3501 struct min_direct *directP;
3509 * Make sure this is an open file
3511 vp = afs_FileTable[dirp->dd_fd];
3518 * If there are no entries in the stream buffer
3519 * then read another chunk
3521 directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3522 if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3524 * set up the uio buffer
3526 iov[0].iov_base = dirp->dd_buf;
3527 iov[0].iov_len = USR_DIRSIZE;
3528 uio.uio_iov = &iov[0];
3530 uio.uio_offset = afs_FileOffsets[dirp->dd_fd];
3532 uio.uio_fmode = FREAD;
3533 uio.uio_resid = USR_DIRSIZE;
3536 * read the next chunk from the directory
3538 code = afs_readdir(VTOAFS(vp), &uio, get_user_struct()->u_cred);
3543 afs_FileOffsets[dirp->dd_fd] = uio.uio_offset;
3545 dirp->dd_size = USR_DIRSIZE - iov[0].iov_len;
3547 directP = (struct min_direct *)(dirp->dd_buf + dirp->dd_loc);
3551 * Check for end of file
3553 if (dirp->dd_size == 0 || directP->d_fileno == 0) {
3557 len = ((sizeof(struct min_direct) + directP->d_namlen + 4) & (~3));
3558 usr_assert(len <= dirp->dd_size);
3561 * Copy the next entry into the usr_dirent structure and advance
3563 direntP = (struct usr_dirent *)(dirp->dd_buf + USR_DIRSIZE);
3564 direntP->d_ino = directP->d_fileno;
3565 direntP->d_off = direntP->d_reclen;
3567 sizeof(struct usr_dirent) - MAXNAMLEN + directP->d_namlen + 1;
3568 memcpy(&direntP->d_name[0], (void *)(directP + 1), directP->d_namlen);
3569 direntP->d_name[directP->d_namlen] = '\0';
3570 dirp->dd_loc += len;
3571 dirp->dd_size -= len;
3580 uafs_closedir(usr_DIR * dirp)
3584 retval = uafs_closedir_r(dirp);
3590 uafs_closedir_r(usr_DIR * dirp)
3601 afs_osi_Free((char *)dirp,
3602 sizeof(usr_DIR) + USR_DIRSIZE + sizeof(struct usr_dirent));
3603 rc = uafs_close_r(fd);
3608 * Destroy AFS credentials from the kernel cache
3615 usr_mutex_lock(&osi_authenticate_lock);
3616 code = ktc_ForgetAllTokens();
3617 usr_mutex_unlock(&osi_authenticate_lock);
3626 retval = uafs_unlog();
3632 * Strip the AFS mount point from a pathname string. Return
3633 * NULL if the path is a relative pathname or if the path
3634 * doesn't start with the AFS mount point string.
3637 uafs_afsPathName(char *path)
3646 for (i = 1, p = path + 1; *p != '\0'; p++) {
3647 /* Ignore duplicate slashes */
3648 if (*p == '/' && lastchar == '/')
3650 /* Is this a subdirectory of the AFS mount point? */
3651 if (afs_mountDir[i] == '\0' && *p == '/') {
3652 /* strip leading slashes */
3653 while (*(++p) == '/');
3656 /* Reject paths that are not within AFS */
3657 if (*p != afs_mountDir[i])
3662 /* Is this the AFS mount point? */
3663 if (afs_mountDir[i] == '\0') {
3664 usr_assert(*p == '\0');
3671 * uafs_getcellstatus
3672 * get the cell status
3675 uafs_getcellstatus(char *cell, afs_int32 * status)
3678 struct afs_ioctl iob;
3681 iob.in_size = strlen(cell) + 1;
3685 rc = call_syscall(AFSCALL_PIOCTL, /*path */ 0, _VICEIOCTL(35),
3693 *status = (intptr_t)iob.out;
3699 * Get quota of volume associated with path
3702 uafs_getvolquota(char *path, afs_int32 * BlocksInUse, afs_int32 * MaxQuota)
3705 struct afs_ioctl iob;
3706 VolumeStatus status;
3710 iob.out = (char *)&status;
3711 iob.out_size = sizeof status;
3713 rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(4), (long)&iob,
3721 *BlocksInUse = status.BlocksInUse;
3722 *MaxQuota = status.MaxQuota;
3728 * Set quota of volume associated with path
3731 uafs_setvolquota(char *path, afs_int32 MaxQuota)
3734 struct afs_ioctl iob;
3735 VolumeStatus status = { 0 };
3737 iob.in = (char *)&status;
3738 iob.in_size = sizeof status;
3742 status.MaxQuota = MaxQuota;
3743 status.MinQuota = -1;
3745 rc = call_syscall(AFSCALL_PIOCTL, (long)path, _VICEIOCTL(5), (long)&iob,
3757 * uafs_statmountpoint
3758 * Determine whether a dir. is a mount point or not
3759 * return 1 if mount point, 0 if not
3762 uafs_statmountpoint(char *path)
3767 retval = uafs_statmountpoint_r(path);
3773 uafs_statmountpoint_r(char *path)
3780 code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1);
3795 * Get a list of rights for the current user on path.
3798 uafs_access(char *path, int flags)
3815 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3822 code = afs_access(VTOAFS(vp), fileMode, get_user_struct()->u_cred);
3829 return code ? -1 : 0;
3834 * Get a list of rights for the current user on path.
3837 uafs_getRights(char *path)
3844 code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0);
3852 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
3853 | PRSFS_LOCK | PRSFS_ADMINISTER;
3855 afs_rights = afs_getRights(VTOAFS(vp), afs_rights, get_user_struct()->u_cred);
3860 #endif /* UKERNEL */