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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * seekdir -- C library extension routine 32 */ 33 34 #include <sys/feature_tests.h> 35 36 #if !defined(_LP64) 37 #pragma weak _seekdir64 = seekdir64 38 #endif 39 #pragma weak _seekdir = seekdir 40 41 #include "lint.h" 42 #include "libc.h" 43 #include <mtlib.h> 44 #include <dirent.h> 45 #include <fcntl.h> 46 #include <unistd.h> 47 48 #ifdef _LP64 49 50 void 51 seekdir(DIR *dirp, long loc) 52 { 53 private_DIR *pdirp = (private_DIR *)dirp; 54 dirent_t *dp; 55 off_t off = 0; 56 57 lmutex_lock(&pdirp->dd_lock); 58 if (lseek(dirp->dd_fd, 0, SEEK_CUR) != 0) { 59 dp = (dirent_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 60 off = dp->d_off; 61 } 62 if (off != loc) { 63 dirp->dd_loc = 0; 64 (void) lseek(dirp->dd_fd, loc, SEEK_SET); 65 dirp->dd_size = 0; 66 67 /* 68 * Save seek offset in d_off field, in case telldir 69 * follows seekdir with no intervening call to readdir 70 */ 71 ((dirent_t *)(uintptr_t)&dirp->dd_buf[0])->d_off = loc; 72 } 73 lmutex_unlock(&pdirp->dd_lock); 74 } 75 76 #else /* _LP64 */ 77 78 /* 79 * Note: Instead of making this function static, we reduce it to local 80 * scope in the mapfile. That allows the linker to prevent it from 81 * appearing in the .SUNW_dynsymsort section. 82 */ 83 void 84 seekdir64(DIR *dirp, off64_t loc) 85 { 86 private_DIR *pdirp = (private_DIR *)(uintptr_t)dirp; 87 dirent64_t *dp64; 88 off64_t off = 0; 89 90 lmutex_lock(&pdirp->dd_lock); 91 if (lseek64(dirp->dd_fd, 0, SEEK_CUR) != 0) { 92 dp64 = (dirent64_t *)(uintptr_t)&dirp->dd_buf[dirp->dd_loc]; 93 /* was converted by readdir and needs to be reversed */ 94 if (dp64->d_ino == (ino64_t)-1) { 95 dirent_t *dp32; 96 97 dp32 = (dirent_t *)((uintptr_t)dp64 + sizeof (ino64_t)); 98 dp64->d_ino = (ino64_t)dp32->d_ino; 99 dp64->d_off = (off64_t)dp32->d_off; 100 dp64->d_reclen = (unsigned short)(dp32->d_reclen + 101 ((char *)&dp64->d_off - (char *)dp64)); 102 } 103 off = dp64->d_off; 104 } 105 if (off != loc) { 106 dirp->dd_loc = 0; 107 (void) lseek64(dirp->dd_fd, loc, SEEK_SET); 108 dirp->dd_size = 0; 109 110 /* 111 * Save seek offset in d_off field, in case telldir 112 * follows seekdir with no intervening call to readdir 113 */ 114 ((dirent64_t *)(uintptr_t)&dirp->dd_buf[0])->d_off = loc; 115 } 116 lmutex_unlock(&pdirp->dd_lock); 117 } 118 119 void 120 seekdir(DIR *dirp, long loc) 121 { 122 seekdir64(dirp, (off64_t)(uint32_t)loc); 123 } 124 125 #endif /* _LP64 */ 126