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 unsigned long VMS_context; 51 char filespec[NAMX_MAXRSS + 1]; 52 char result[NAMX_MAXRSS + 1]; 53 struct dsc$descriptor_d filespec_dsc; 54 struct dsc$descriptor_d result_dsc; 55}; 56 57const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory) 58{ 59 int status; 60 char *p, *r; 61 size_t l; 62 unsigned long flags = 0; 63 64/* Arrange 32-bit pointer to (copied) string storage, if needed. */ 65#if __INITIAL_POINTER_SIZE == 64 66# pragma pointer_size save 67# pragma pointer_size 32 68 char *ctx_filespec_32p; 69# pragma pointer_size restore 70 char ctx_filespec_32[NAMX_MAXRSS + 1]; 71#endif /* __INITIAL_POINTER_SIZE == 64 */ 72 73#ifdef NAML$C_MAXRSS 74 flags |= LIB$M_FIL_LONG_NAMES; 75#endif 76 77 if (ctx == NULL || directory == NULL) { 78 errno = EINVAL; 79 return 0; 80 } 81 82 errno = 0; 83 if (*ctx == NULL) { 84 size_t filespeclen = strlen(directory); 85 char *filespec = NULL; 86 87 if (filespeclen == 0) { 88 errno = ENOENT; 89 return 0; 90 } 91 92 /* MUST be a VMS directory specification! Let's estimate if it is. */ 93 if (directory[filespeclen - 1] != ']' 94 && directory[filespeclen - 1] != '>' 95 && directory[filespeclen - 1] != ':') { 96 errno = EINVAL; 97 return 0; 98 } 99 100 filespeclen += 4; /* "*.*;" */ 101 102 if (filespeclen > NAMX_MAXRSS) { 103 errno = ENAMETOOLONG; 104 return 0; 105 } 106 107 *ctx = (LP_DIR_CTX *)malloc(sizeof(LP_DIR_CTX)); 108 if (*ctx == NULL) { 109 errno = ENOMEM; 110 return 0; 111 } 112 memset(*ctx, '\0', sizeof(LP_DIR_CTX)); 113 114 strcpy((*ctx)->filespec, directory); 115 strcat((*ctx)->filespec, "*.*;"); 116 117/* Arrange 32-bit pointer to (copied) string storage, if needed. */ 118#if __INITIAL_POINTER_SIZE == 64 119# define CTX_FILESPEC ctx_filespec_32p 120 /* Copy the file name to storage with a 32-bit pointer. */ 121 ctx_filespec_32p = ctx_filespec_32; 122 strcpy(ctx_filespec_32p, (*ctx)->filespec); 123#else /* __INITIAL_POINTER_SIZE == 64 */ 124# define CTX_FILESPEC (*ctx)->filespec 125#endif /* __INITIAL_POINTER_SIZE == 64 [else] */ 126 127 (*ctx)->filespec_dsc.dsc$w_length = filespeclen; 128 (*ctx)->filespec_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 129 (*ctx)->filespec_dsc.dsc$b_class = DSC$K_CLASS_S; 130 (*ctx)->filespec_dsc.dsc$a_pointer = CTX_FILESPEC; 131 } 132 133 (*ctx)->result_dsc.dsc$w_length = 0; 134 (*ctx)->result_dsc.dsc$b_dtype = DSC$K_DTYPE_T; 135 (*ctx)->result_dsc.dsc$b_class = DSC$K_CLASS_D; 136 (*ctx)->result_dsc.dsc$a_pointer = 0; 137 138 status = lib$find_file(&(*ctx)->filespec_dsc, &(*ctx)->result_dsc, 139 &(*ctx)->VMS_context, 0, 0, 0, &flags); 140 141 if (status == RMS$_NMF) { 142 errno = 0; 143 vaxc$errno = status; 144 return NULL; 145 } 146 147 if (!$VMS_STATUS_SUCCESS(status)) { 148 errno = EVMSERR; 149 vaxc$errno = status; 150 return NULL; 151 } 152 153 /* 154 * Quick, cheap and dirty way to discard any device and directory, since 155 * we only want file names 156 */ 157 l = (*ctx)->result_dsc.dsc$w_length; 158 p = (*ctx)->result_dsc.dsc$a_pointer; 159 r = p; 160 for (; *p; p++) { 161 if (*p == '^' && p[1] != '\0') { /* Take care of ODS-5 escapes */ 162 p++; 163 } else if (*p == ':' || *p == '>' || *p == ']') { 164 l -= p + 1 - r; 165 r = p + 1; 166 } else if (*p == ';') { 167 l = p - r; 168 break; 169 } 170 } 171 172 strncpy((*ctx)->result, r, l); 173 (*ctx)->result[l] = '\0'; 174 str$free1_dx(&(*ctx)->result_dsc); 175 176 return (*ctx)->result; 177} 178 179int LP_find_file_end(LP_DIR_CTX **ctx) 180{ 181 if (ctx != NULL && *ctx != NULL) { 182 int status = lib$find_file_end(&(*ctx)->VMS_context); 183 184 free(*ctx); 185 186 if (!$VMS_STATUS_SUCCESS(status)) { 187 errno = EVMSERR; 188 vaxc$errno = status; 189 return 0; 190 } 191 return 1; 192 } 193 errno = EINVAL; 194 return 0; 195} 196