1/* 2 * Copyright (c) 2004, Richard Levitte <richard@levitte.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <stddef.h> 28#include <stdlib.h> 29#include <string.h> 30#include <errno.h> 31#include <descrip.h> 32#include <namdef.h> 33#include <rmsdef.h> 34#include <libfildef.h> 35#include <lib$routines.h> 36#include <strdef.h> 37#include <str$routines.h> 38#include <stsdef.h> 39#ifndef LPDIR_H 40#include "LPdir.h" 41#endif 42#include "vms_rms.h" 43 44/* Some compiler options hide EVMSERR. */ 45#ifndef EVMSERR 46# define EVMSERR 65535 /* error for non-translatable VMS errors */ 47#endif 48 49struct LP_dir_context_st 50{ 51 unsigned long VMS_context; 52 char filespec[ NAMX_MAXRSS+ 1]; 53 char result[ NAMX_MAXRSS+ 1]; 54 struct dsc$descriptor_d filespec_dsc; 55 struct dsc$descriptor_d result_dsc; 56}; 57 58const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory) 59{ 60 int status; 61 char *p, *r; 62 size_t l; 63 unsigned long flags = 0; 64 65/* Arrange 32-bit pointer to (copied) string storage, if needed. */ 66#if __INITIAL_POINTER_SIZE == 64 67# pragma pointer_size save 68# pragma pointer_size 32 69 char *ctx_filespec_32p; 70# pragma pointer_size restore 71 char ctx_filespec_32[ NAMX_MAXRSS+ 1]; 72#endif /* __INITIAL_POINTER_SIZE == 64 */ 73 74#ifdef NAML$C_MAXRSS 75 flags |= LIB$M_FIL_LONG_NAMES; 76#endif 77 78 if (ctx == NULL || directory == NULL) 79 { 80 errno = EINVAL; 81 return 0; 82 } 83 84 errno = 0; 85 if (*ctx == NULL) 86 { 87 size_t filespeclen = strlen(directory); 88 char *filespec = NULL; 89 90 if (filespeclen == 0) 91 { 92 errno = ENOENT; 93 return 0; 94 } 95 96 /* MUST be a VMS directory specification! Let's estimate if it is. */ 97 if (directory[filespeclen-1] != ']' 98 && directory[filespeclen-1] != '>' 99 && directory[filespeclen-1] != ':') 100 { 101 errno = EINVAL; 102 return 0; 103 } 104 105 filespeclen += 4; /* "*.*;" */ 106 107 if (filespeclen > NAMX_MAXRSS) 108 { 109 errno = ENAMETOOLONG; 110 return 0; 111 } 112 113 *ctx = (LP_DIR_CTX *)malloc(sizeof(LP_DIR_CTX)); 114 if (*ctx == NULL) 115 { 116 errno = ENOMEM; 117 return 0; 118 } 119 memset(*ctx, '\0', sizeof(LP_DIR_CTX)); 120 121 strcpy((*ctx)->filespec,directory); 122 strcat((*ctx)->filespec,"*.*;"); 123 124/* Arrange 32-bit pointer to (copied) string storage, if needed. */ 125#if __INITIAL_POINTER_SIZE == 64 126# define CTX_FILESPEC ctx_filespec_32p 127 /* Copy the file name to storage with a 32-bit pointer. */ 128 ctx_filespec_32p = ctx_filespec_32; 129 strcpy( ctx_filespec_32p, (*ctx)->filespec); 130#else /* __INITIAL_POINTER_SIZE == 64 */ 131# define CTX_FILESPEC (*ctx)->filespec 132#endif /* __INITIAL_POINTER_SIZE == 64 [else] */ 133 134 (*ctx)->filespec_dsc.dsc$w_length = filespeclen; 135 (*ctx)->filespec_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 136 (*ctx)->filespec_dsc.dsc$b_class = DSC$K_CLASS_S; 137 (*ctx)->filespec_dsc.dsc$a_pointer = CTX_FILESPEC; 138 } 139 140 (*ctx)->result_dsc.dsc$w_length = 0; 141 (*ctx)->result_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 142 (*ctx)->result_dsc.dsc$b_class = DSC$K_CLASS_D; 143 (*ctx)->result_dsc.dsc$a_pointer = 0; 144 145 status = lib$find_file(&(*ctx)->filespec_dsc, &(*ctx)->result_dsc, 146 &(*ctx)->VMS_context, 0, 0, 0, &flags); 147 148 if (status == RMS$_NMF) 149 { 150 errno = 0; 151 vaxc$errno = status; 152 return NULL; 153 } 154 155 if(!$VMS_STATUS_SUCCESS(status)) 156 { 157 errno = EVMSERR; 158 vaxc$errno = status; 159 return NULL; 160 } 161 162 /* Quick, cheap and dirty way to discard any device and directory, 163 since we only want file names */ 164 l = (*ctx)->result_dsc.dsc$w_length; 165 p = (*ctx)->result_dsc.dsc$a_pointer; 166 r = p; 167 for (; *p; p++) 168 { 169 if (*p == '^' && p[1] != '\0') /* Take care of ODS-5 escapes */ 170 { 171 p++; 172 } 173 else if (*p == ':' || *p == '>' || *p == ']') 174 { 175 l -= p + 1 - r; 176 r = p + 1; 177 } 178 else if (*p == ';') 179 { 180 l = p - r; 181 break; 182 } 183 } 184 185 strncpy((*ctx)->result, r, l); 186 (*ctx)->result[l] = '\0'; 187 str$free1_dx(&(*ctx)->result_dsc); 188 189 return (*ctx)->result; 190} 191 192int LP_find_file_end(LP_DIR_CTX **ctx) 193{ 194 if (ctx != NULL && *ctx != NULL) 195 { 196 int status = lib$find_file_end(&(*ctx)->VMS_context); 197 198 free(*ctx); 199 200 if(!$VMS_STATUS_SUCCESS(status)) 201 { 202 errno = EVMSERR; 203 vaxc$errno = status; 204 return 0; 205 } 206 return 1; 207 } 208 errno = EINVAL; 209 return 0; 210} 211 212