@@ -152,9 +152,10 @@ void ods2_head_to_stat( const struct HEAD *head, struct stat *st ) {
152152 st -> st_gid = (gid_t )F11WORD ( head -> fh2$l_fileowner .uic$w_grp );
153153
154154 /* Times. IDENT area lives at fh2$b_idoffset (units of words). */
155- if ( head -> fh2$b_idoffset >= FH2$C_LENGTH / 2 ) {
155+ size_t idoff = (size_t )head -> fh2$b_idoffset * sizeof (f11word );
156+ if ( idoff >= FH2$C_LENGTH && idoff + sizeof (struct IDENT ) <= sizeof * head ) {
156157 const struct IDENT * id = (const struct IDENT * )
157- ((const uint16_t * )head + head -> fh2$b_idoffset );
158+ ((const char * )head + idoff );
158159 st -> st_mtime = ods2_vmstime_to_time_t ( id -> fi2$q_revdate );
159160 st -> st_ctime = ods2_vmstime_to_time_t ( id -> fi2$q_credate );
160161 st -> st_atime = st -> st_mtime ;
@@ -183,20 +184,24 @@ static char *split_last( char *path ) {
183184 * argument expected by direct_dirid(). Empty input -> empty output
184185 * (which direct_dirid() treats as MFD).
185186 */
186- static void posix_dir_to_vms ( const char * posix , char * out , size_t outlen ) {
187+ static int posix_dir_to_vms ( const char * posix , char * out , size_t outlen ) {
187188 size_t o = 0 ;
188189 int first = 1 ;
189- if ( outlen == 0 ) return ;
190+ if ( outlen == 0 ) return 0 ;
190191 for ( const char * p = posix ; * p && o + 1 < outlen ; ) {
191192 while ( * p == '/' ) ++ p ;
192193 if ( !* p ) break ;
193194 if ( !first && o + 1 < outlen )
194195 out [o ++ ] = '.' ;
195196 first = 0 ;
196- while ( * p && * p != '/' && o + 1 < outlen )
197+ while ( * p && * p != '/' ) {
198+ if ( o + 1 >= outlen )
199+ return 0 ;
197200 out [o ++ ] = (char )toupper ( (unsigned char )* p ++ );
201+ }
198202 }
199203 out [o ] = '\0' ;
204+ return 1 ;
200205}
201206
202207/* Parse "FILE.EXT" or "FILE.EXT;n" into (name, version). When no
@@ -264,6 +269,7 @@ vmscond_t ods2_iterate_dir( struct FCB *dir_fcb, int latest_only,
264269 char last_name [128 ];
265270 int last_name_len = -1 ;
266271 int stop = 0 ;
272+ vmscond_t retsts = SS$_NORMAL ;
267273
268274 for ( uint32_t blk = 1 ; blk <= efblk && !stop ; ++ blk ) {
269275 struct VIOC * vioc = NULL ;
@@ -299,23 +305,30 @@ vmscond_t ods2_iterate_dir( struct FCB *dir_fcb, int latest_only,
299305 fprintf ( stderr ,
300306 "fuse-ods2: iterate_dir: record size=%u too big at offs=%ld\n" ,
301307 (unsigned )size , (long )(p - buf ) );
308+ retsts = SS$_BADIRECTORY ;
309+ stop = 1 ;
302310 break ;
303311 }
304312 if ( p + size + 2 > end ) {
305313 if ( ods2_rt .debug )
306314 fprintf ( stderr ,
307315 "fuse-ods2: iterate_dir: record overruns block at offs=%ld size=%u\n" ,
308316 (long )(p - buf ), (unsigned )size );
317+ retsts = SS$_BADIRECTORY ;
318+ stop = 1 ;
309319 break ;
310320 }
311321
312322 uint8_t namecount = dr -> dir$b_namecount ;
313323 char * namebase = dr -> dir$t_name ;
314- if ( namebase + namecount > end ) {
324+ char * rec_end = (char * )dr + size + 2 ;
325+ if ( namebase + namecount > rec_end ) {
315326 if ( ods2_rt .debug )
316327 fprintf ( stderr ,
317328 "fuse-ods2: iterate_dir: name overruns block (count=%u)\n" ,
318329 (unsigned )namecount );
330+ retsts = SS$_BADIRECTORY ;
331+ stop = 1 ;
319332 break ;
320333 }
321334 if ( ods2_rt .debug )
@@ -332,7 +345,6 @@ vmscond_t ods2_iterate_dir( struct FCB *dir_fcb, int latest_only,
332345 && memcmp ( last_name , namebase , namecount ) == 0 );
333346
334347 char * eptr = namebase + ((namecount + 1 ) & ~1 );
335- char * rec_end = (char * )dr + size + 2 ;
336348 int first = 1 ;
337349 while ( eptr + sizeof (struct dir$r_ent ) <= rec_end ) {
338350 struct dir$r_ent * de = (struct dir$r_ent * )eptr ;
@@ -363,7 +375,7 @@ vmscond_t ods2_iterate_dir( struct FCB *dir_fcb, int latest_only,
363375 deaccesschunk ( vioc , 0 , 0 , 1 );
364376 }
365377
366- return SS$_NORMAL ;
378+ return retsts ;
367379}
368380
369381/* ------------------------------------------------------ path resolver */
@@ -412,7 +424,7 @@ vmscond_t ods2_path_to_fid( const char *path, struct fiddef *out_fid,
412424 return SS$_BADPARAM ;
413425
414426 /* Root and "/000000" both map to the MFD. */
415- if ( strcmp ( path , "/" ) == 0 ) {
427+ if ( strcmp ( path , "/" ) == 0 || strcmp ( path , "/000000" ) == 0 ) {
416428 out_fid -> fid$w_num = FID$C_MFD ;
417429 out_fid -> fid$w_seq = FID$C_MFD ;
418430 out_fid -> fid$b_rvn = 0 ;
@@ -439,7 +451,10 @@ vmscond_t ods2_path_to_fid( const char *path, struct fiddef *out_fid,
439451
440452 /* "work" now holds the dir prefix (with leading '/') or empty. */
441453 char vmsdir [512 ];
442- posix_dir_to_vms ( work , vmsdir , sizeof vmsdir );
454+ if ( !posix_dir_to_vms ( work , vmsdir , sizeof vmsdir ) ) {
455+ free ( work );
456+ return SS$_BADFILENAME ;
457+ }
443458
444459 /* Resolve directory part. */
445460 struct dsc_descriptor dirdsc ;
0 commit comments