1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <string.h> 29 #include <stddef.h> 30 #include <errno.h> 31 #include <unistd.h> 32 #include <assert.h> 33 #include <sys/types.h> 34 #include <sys/systm.h> 35 #include <sys/dirent.h> 36 #include <sys/lx_misc.h> 37 #include <sys/lx_debug.h> 38 39 #define LX_NAMEMAX 256 40 41 struct lx_dirent { 42 long d_ino; /* not l_ino_t */ 43 long d_off; 44 ushort_t d_reclen; 45 char d_name[LX_NAMEMAX]; 46 }; 47 48 struct lx_dirent64 { 49 uint64_t d_ino; 50 int64_t d_off; 51 ushort_t d_reclen; 52 uchar_t d_type; 53 char d_name[LX_NAMEMAX]; 54 }; 55 56 #define LX_RECLEN(namelen) \ 57 ((offsetof(struct lx_dirent64, d_name) + 1 + (namelen) + 7) & ~7) 58 59 /* 60 * Read in one dirent structure from fd into dirp. 61 * p3 (count) is ignored. 62 */ 63 /*ARGSUSED*/ 64 int 65 lx_readdir(uintptr_t p1, uintptr_t p2, uintptr_t p3) 66 { 67 int fd = (int)p1; 68 struct lx_dirent *dirp = (struct lx_dirent *)p2; 69 uint_t count = sizeof (struct lx_dirent); 70 int rc = 0; 71 struct lx_dirent _ld; 72 struct dirent *sd = (struct dirent *)&_ld; 73 74 /* 75 * The return value from getdents is not applicable, as 76 * it might have squeezed more than one dirent in the buffer 77 * we provided. 78 * 79 * getdents() will deal with the case of dirp == NULL 80 */ 81 if ((rc = getdents(fd, sd, count)) < 0) 82 return (-errno); 83 84 /* 85 * Set rc 1 (pass), or 0 (end of directory). 86 */ 87 rc = (sd->d_reclen == 0) ? 0 : 1; 88 89 if (uucopy(sd, dirp, count) != 0) 90 return (-errno); 91 92 return (rc); 93 } 94 95 /* 96 * Read in dirent64 structures from p1 (fd) into p2 (buffer). 97 * p3 (count) is the size of the memory area. 98 */ 99 int 100 lx_getdents64(uintptr_t p1, uintptr_t p2, uintptr_t p3) 101 { 102 int fd = (uint_t)p1; 103 void *buf = (void *)p2; 104 void *sbuf, *lbuf; 105 int lbufsz = (uint_t)p3; 106 int sbufsz; 107 int namelen; 108 struct dirent *sd; 109 struct lx_dirent64 *ld; 110 int bytes, rc; 111 112 if (lbufsz < sizeof (struct lx_dirent64)) 113 return (-EINVAL); 114 115 /* 116 * The Linux dirent64 is bigger than the Solaris dirent64. To 117 * avoid inadvertently consuming more of the directory than we can 118 * pass back to the Linux app, we hand the kernel a smaller buffer 119 * than the app handed us. 120 */ 121 sbufsz = (lbufsz / 32) * 24; 122 123 sbuf = SAFE_ALLOCA(sbufsz); 124 lbuf = SAFE_ALLOCA(lbufsz); 125 if (sbuf == NULL || lbuf == NULL) 126 return (-ENOMEM); 127 128 if ((bytes = getdents(fd, sbuf, sbufsz)) < 0) 129 return (-errno); 130 131 /* munge the Solaris buffer to a linux buffer. */ 132 sd = (struct dirent *)sbuf; 133 ld = (struct lx_dirent64 *)lbuf; 134 rc = 0; 135 while (bytes > 0) { 136 namelen = strlen(sd->d_name); 137 if (namelen >= LX_NAMEMAX) 138 namelen = LX_NAMEMAX - 1; 139 ld->d_ino = (uint64_t)sd->d_ino; 140 ld->d_off = (int64_t)sd->d_off; 141 ld->d_type = 0; 142 143 (void) strncpy(ld->d_name, sd->d_name, namelen); 144 ld->d_name[namelen] = 0; 145 ld->d_reclen = (ushort_t)LX_RECLEN(namelen); 146 147 bytes -= (int)sd->d_reclen; 148 rc += (int)ld->d_reclen; 149 150 sd = (struct dirent *)(void *)((caddr_t)sd + sd->d_reclen); 151 ld = (struct lx_dirent64 *)(void *)((caddr_t)ld + ld->d_reclen); 152 } 153 154 /* now copy the lbuf to the userland buffer */ 155 assert(rc <= lbufsz); 156 if (uucopy(lbuf, buf, rc) != 0) 157 return (-EFAULT); 158 159 return (rc); 160 }