This file is indexed.

/usr/lib/grass70/include/grass/iostream/ami_stream.h is in grass-dev 7.0.3-1build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
/****************************************************************************
 * 
 *  MODULE:     iostream
 *

 *  COPYRIGHT (C) 2007 Laura Toma
 *   
 * 

 *  Iostream is a library that implements streams, external memory
 *  sorting on streams, and an external memory priority queue on
 *  streams. These are the fundamental components used in external
 *  memory algorithms.  

 * Credits: The library was developed by Laura Toma.  The kernel of
 * class STREAM is based on the similar class existent in the GPL TPIE
 * project developed at Duke University. The sorting and priority
 * queue have been developed by Laura Toma based on communications
 * with Rajiv Wickremesinghe. The library was developed as part of
 * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
 * Rajiv Wickremesinghe as part of the Terracost project.

 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.  *
 *  **************************************************************************/



#ifndef _AMI_STREAM_H
#define _AMI_STREAM_H

#include <grass/config.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

#include <cstring>
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
using std::ostream;
using std::ofstream;
using std::istream;

extern "C" {
#include <grass/gis.h>
}

#define MAX_STREAMS_OPEN 200

#include "mm.h" // Get the memory manager.

#define DEBUG_DELETE if(0)
#define DEBUG_STREAM_LEN if(0)
#define DEBUG_ASSERT if(0)

// The name of the environment variable which keeps the name of the
// directory where streams are stored
#define STREAM_TMPDIR "STREAM_DIR"

// All streams will be names STREAM_*****
#define BASE_NAME "STREAM"

#define STREAM_BUFFER_SIZE (1<<18)


//
// AMI error codes are returned using the AMI_err type.
//
enum AMI_err {
  AMI_ERROR_NO_ERROR = 0,
  AMI_ERROR_IO_ERROR,
  AMI_ERROR_END_OF_STREAM,
  AMI_ERROR_OUT_OF_RANGE,
  AMI_ERROR_READ_ONLY,
  AMI_ERROR_OS_ERROR,
  AMI_ERROR_MM_ERROR,
  AMI_ERROR_OBJECT_INITIALIZATION,
  AMI_ERROR_PERMISSION_DENIED,
  AMI_ERROR_INSUFFICIENT_MAIN_MEMORY,
  AMI_ERROR_INSUFFICIENT_AVAILABLE_STREAMS,
  AMI_ERROR_ENV_UNDEFINED,
  AMI_ERROR_NO_MAIN_MEMORY_OPERATION,
};

extern const char *ami_str_error[];

//
// AMI stream types passed to constructors
//
enum AMI_stream_type {
    AMI_READ_STREAM = 1,	// Open existing stream for reading
    AMI_WRITE_STREAM,		// Open for writing.  Create if non-existent
    AMI_APPEND_STREAM,		// Open for writing at end.  Create if needed.
    AMI_READ_WRITE_STREAM,	// Open to read and write.
    AMI_APPEND_WRITE_STREAM 	// Open for writing at end (write only mode).
};




enum persistence {
    // Delete the stream from the disk when it is destructed.
  PERSIST_DELETE = 0,
  // Do not delete the stream from the disk when it is destructed.
  PERSIST_PERSISTENT,
  // Delete each block of data from the disk as it is read.
  PERSIST_READ_ONCE
};

/* an un-templated version makes for easier debugging */
class UntypedStream {
protected:
  FILE * fp;
  int fildes;	//descriptor of file
  AMI_stream_type  access_mode;
  char path[BUFSIZ];
  persistence per;

  //0 for streams, positive for substreams
  unsigned int substream_level;
  
  // If this stream is actually a substream, these will be set to
  // indicate the portion of the file that is part of this stream.  If
  // the stream is the whole file, they will be set to -1. Both are in
  // T units.
  off_t logical_bos;
  off_t logical_eos;

  //stream buffer passed in the call to setvbuf when file is opened
  char* buf;
  int eof_reached;

 public:
  static unsigned int get_block_length()  {
    return STREAM_BUFFER_SIZE;
    //return getpagesize();
  };

};

template<class T> 
class AMI_STREAM : public UntypedStream {

protected:

  T read_tmp;					/* this is ugly... RW */

public:
  // An AMI_stream with default name
  AMI_STREAM();
  
  // An AMI stream based on a specific path name.
  AMI_STREAM(const char *path_name, AMI_stream_type st = AMI_READ_WRITE_STREAM);

  // convenience function with split path_name
  //AMI_STREAM(const char *dir_name, const char *file_name, AMI_stream_type st);
  
  
  // A psuedo-constructor for substreams.
  AMI_err new_substream(AMI_stream_type st, off_t sub_begin, off_t sub_end,
			AMI_STREAM<T> **sub_stream);

  // Destructor
  ~AMI_STREAM(void);
  
  // Read and write elements.
  AMI_err read_item(T **elt);
  AMI_err write_item(const T &elt);
  AMI_err read_array(T *data, off_t len, off_t *lenp=NULL);
  AMI_err write_array(const T *data, off_t len);
  
  // Return the number of items in the stream.
  off_t stream_len(void);
  
  // Return the path name of this stream.
  AMI_err name(char **stream_name);
  const char* name() const;
  
  // Move to a specific item in the stream.
  AMI_err seek(off_t offset);

  // Query memory usage
  static AMI_err main_memory_usage(size_t *usage,
			    MM_stream_usage usage_type= MM_STREAM_USAGE_OVERHEAD);
  
  void persist(persistence p);
  
  char *sprint();

  // have we hit the end of the stream
  int eof();
};


/**********************************************************************/


/**********************************************************************/
/* creates a random file name, opens the file for reading and writing
   and and returns a file descriptor */
/* int ami_single_temp_name(char *base, char* tmp_path); */
/* fix from Andy Danner */
int ami_single_temp_name(const std::string& base, char* tmp_path); 


/**********************************************************************/
/* given fd=fide descriptor, associates with it a stream aopened in
   access_mode and returns it */
FILE*  open_stream(int fd, AMI_stream_type st);


/**********************************************************************/
/* open the file whose name is pathname in access mode */
FILE* open_stream(char* pathname, AMI_stream_type st);




/********************************************************************/
//  An  AMI stream with default name.
template<class T>
AMI_STREAM<T>::AMI_STREAM() {
  
  access_mode = AMI_READ_WRITE_STREAM;
  int fd = ami_single_temp_name(BASE_NAME, path);
  fildes = fd;
  fp = open_stream(fd, access_mode);
  
  /* a stream is by default buffered with a buffer of size BUFSIZ=1K */
  buf = new char[STREAM_BUFFER_SIZE];
  if (setvbuf(fp, buf, _IOFBF, STREAM_BUFFER_SIZE) != 0) {
    cerr << "ERROR: setvbuf failed (stream " << path << ") with: "
         << strerror(errno) << endl;
    exit(1);
  }
  
  // By default, all streams are deleted at destruction time.
  per = PERSIST_DELETE;

   // Not a substream.
  substream_level  = 0;
  logical_bos = logical_eos = -1;

  // why is this here in the first place?? -RW
  seek(0);

  eof_reached = 0;

  // Register memory usage before returning.
  //size_t usage; 
  //main_memory_usage(&usage,  MM_STREAM_USAGE_CURRENT);
  //MM_manager.register_allocation(usage);
}



/**********************************************************************/
// An AMI stream based on a specific path name.
template<class T>
AMI_STREAM<T>::AMI_STREAM(const char *path_name, AMI_stream_type st) {

  access_mode = st;

  if(path_name == NULL) {
	int fd = ami_single_temp_name(BASE_NAME, path);
	fildes = fd;
	fp = open_stream(fd, access_mode);
  } else {
	strcpy(path, path_name);
	fp = open_stream(path, st);  
	fildes = -1;
  }

  /* a stream is by default buffered with a buffer of size BUFSIZ=1K */
  buf = new char[STREAM_BUFFER_SIZE];
  if (setvbuf(fp, buf, _IOFBF, STREAM_BUFFER_SIZE) != 0) {
    cerr << "ERROR: setvbuf failed (stream " << path << ") with: "
         << strerror(errno) << endl;
    exit(1);
  }

  eof_reached = 0;

  // By default, all streams are deleted at destruction time.
  if(st == AMI_READ_STREAM) {
	per = PERSIST_PERSISTENT;
  } else {
	per = PERSIST_DELETE;
  }

  // Not a substream.
  substream_level  = 0;
  logical_bos = logical_eos = -1;
  
  seek(0);

  // Register memory usage before returning.
  //size_t usage; 
  //main_memory_usage(&usage,  MM_STREAM_USAGE_CURRENT);
  //MM_manager.register_allocation(usage);
};



/**********************************************************************/
 // A psuedo-constructor for substreams.
template<class T>
AMI_err AMI_STREAM<T>::new_substream(AMI_stream_type st,
				     off_t sub_begin,
				     off_t sub_end,
				     AMI_STREAM<T> **sub_stream) {

  //assume this for now
  assert(st == AMI_READ_STREAM);

#ifdef __MINGW32__
  /* MINGW32: reopen file here for stream_len() below */
  //reopen the file 
  AMI_STREAM<T> *substr = new AMI_STREAM<T>(path, st);
#endif

  //check range
  if (substream_level) {
     if( (sub_begin >= (logical_eos - logical_bos)) ||
	 (sub_end >= (logical_eos - logical_bos)) ) {
       
       return AMI_ERROR_OUT_OF_RANGE;
     }
  }  else {
    off_t len = stream_len();
    if (sub_begin > len || sub_end > len) {

      return AMI_ERROR_OUT_OF_RANGE;
    }
  }

#ifndef __MINGW32__
  //reopen the file 
  AMI_STREAM<T> *substr = new AMI_STREAM<T>(path, st);
#endif

  // Set up the beginning and end positions.
  if (substream_level) {
    substr->logical_bos = logical_bos + sub_begin;
    substr->logical_eos = logical_bos + sub_end + 1;
  } else {
    substr->logical_bos = sub_begin;
    substr->logical_eos = sub_end + 1;
  }
  
  // Set the current position.
  substr->seek(0);

  substr->eof_reached = 0;

  //set substream level
  substr->substream_level = substream_level + 1;

  substr->per = per;   //set persistence

  //*sub_stream = (AMI_base_stream < T > *)substr;
  *sub_stream = substr;
  return  AMI_ERROR_NO_ERROR;
};



/**********************************************************************/
// Return the number of items in the stream.
template<class T>
off_t AMI_STREAM<T>::stream_len(void) {

  fflush(fp);

#ifdef __MINGW32__
  //stat() fails on MS Windows if the file is open, so try G_ftell() instead.
  //FIXME: not 64bit safe, but WinGrass isn't either right now.
  off_t posn_save, st_size;

  posn_save = G_ftell(fp);
  if(posn_save == -1) {
     perror("ERROR: AMI_STREAM::stream_len(): ftell(fp) failed ");
     perror(path);
     exit(1);
  }

  G_fseek(fp, 0, SEEK_END);
  st_size = G_ftell(fp);
  if(st_size == -1) {
     perror("ERROR: AMI_STREAM::stream_len(): ftell[SEEK_END] failed ");
     perror(path);
     exit(1);
  }

  G_fseek(fp, posn_save, SEEK_SET);

  //debug stream_len:
  DEBUG_STREAM_LEN fprintf(stderr, "%s: length = %lld   sizeof(T)=%d\n",
	  path, st_size, sizeof(T));

  return (st_size / sizeof(T));
#else
  struct stat buf;
  if (stat(path, &buf) == -1) {
    perror("AMI_STREAM::stream_len(): fstat failed ");
    DEBUG_ASSERT assert(0);
    exit(1);
  }

  //debug stream_len:
  DEBUG_STREAM_LEN fprintf(stderr, "%s: length = %lld   sizeof(T)=%lud\n",
	  path, (long long int)buf.st_size, sizeof(T));

  return (buf.st_size / sizeof(T));
#endif
};



/**********************************************************************/
// Return the path name of this stream.
template<class T>
AMI_err AMI_STREAM<T>::name(char **stream_name)  {
  
  *stream_name = new char [strlen(path) + 1];
  strcpy(*stream_name, path);
  
  return AMI_ERROR_NO_ERROR;
};

// Return the path name of this stream.
template<class T>
const char *
AMI_STREAM<T>::name() const {
  return path;
};



/**********************************************************************/
// Move to a specific offset within the (sub)stream.
template<class T>
AMI_err AMI_STREAM<T>::seek(off_t offset) {

  off_t seek_offset;
  
  if (substream_level) {    //substream
    if (offset  > (unsigned) (logical_eos - logical_bos)) {
      //offset out of range
      cerr << "ERROR: AMI_STREAM::seek bos=" << logical_bos << ", eos="
           << logical_eos << ", offset " << offset << " out of range.\n";
      DEBUG_ASSERT assert(0);
      exit(1);
    } else {
      //offset in range 
      seek_offset = (logical_bos + offset) * sizeof(T);
    }


  } else {
    //not a substream
    seek_offset = offset * sizeof(T);
  }

  G_fseek(fp, seek_offset, SEEK_SET);
  
  return AMI_ERROR_NO_ERROR;
}




/**********************************************************************/
// Query memory usage
template<class T>
AMI_err
AMI_STREAM<T>::main_memory_usage(size_t *usage, MM_stream_usage usage_type) {
  
   switch (usage_type) {
   case MM_STREAM_USAGE_OVERHEAD:
     *usage = sizeof (AMI_STREAM<T>);
     break;
   case MM_STREAM_USAGE_BUFFER:
     // *usage = get_block_length();
     *usage = STREAM_BUFFER_SIZE*sizeof(char);
     break;
   case MM_STREAM_USAGE_CURRENT:
   case MM_STREAM_USAGE_MAXIMUM:
     // *usage = sizeof (*this) + get_block_length();
     *usage = sizeof (AMI_STREAM<T>) + STREAM_BUFFER_SIZE*sizeof(char);
     break;
   }
   return AMI_ERROR_NO_ERROR;
};



/**********************************************************************/
template<class T>
AMI_STREAM<T>::~AMI_STREAM(void)  {
  
  DEBUG_DELETE cerr << "~AMI_STREAM: " << path << "(" << this << ")\n";
  assert(fp);
  fclose(fp);
  delete buf;
  
  // Get rid of the file if not persistent and if not substream.
  if ((per != PERSIST_PERSISTENT) && (substream_level == 0)) {
    if (unlink(path) == -1) {
      cerr << "ERROR: AMI_STREAM: failed to unlink " << path << endl;
      perror("cannot unlink: ");
      DEBUG_ASSERT assert(0);
      exit(1);
    }
  }
  // Register memory deallocation before returning.
  //size_t usage; 
  //main_memory_usage(&usage,  MM_STREAM_USAGE_CURRENT);
  //MM_manager.register_deallocation(usage);
 };



/**********************************************************************/
template<class T>
AMI_err AMI_STREAM<T>::read_item(T **elt)  {

  assert(fp);

  //if we go past substream range
  if ((logical_eos >= 0) && G_ftell(fp) >= sizeof(T) * logical_eos) {
    return AMI_ERROR_END_OF_STREAM;
  
  } else {
    if (fread((char *) (&read_tmp), sizeof(T), 1, fp) < 1) {
      if(feof(fp)) {
	eof_reached = 1;
	return AMI_ERROR_END_OF_STREAM;
      } else {
	cerr << "ERROR: file=" << path << ":";
	perror("cannot read!");    
	return AMI_ERROR_IO_ERROR;
      }
    }
    
    *elt = &read_tmp;
    return AMI_ERROR_NO_ERROR; 
  }
};




/**********************************************************************/
template<class T>
AMI_err AMI_STREAM<T>::read_array(T *data, off_t len, off_t *lenp) {
  size_t nobj;
  assert(fp);
  
  //if we go past substream range
  if ((logical_eos >= 0) && G_ftell(fp) >= sizeof(T) * logical_eos) {
	eof_reached = 1;
    return AMI_ERROR_END_OF_STREAM;
    
  } else {
    nobj = fread((void*)data, sizeof(T), len, fp);

    if (nobj < len) {		/* some kind of error */
      if(feof(fp)) {
	if(lenp) *lenp = nobj;
	eof_reached = 1;
	return AMI_ERROR_END_OF_STREAM;
      } else {
	cerr << "ERROR: file=" << path << ":";
	perror("cannot read!");    
	return AMI_ERROR_IO_ERROR;
      }
    }
    if(lenp) *lenp = nobj;
    return AMI_ERROR_NO_ERROR; 
  }
};




/**********************************************************************/
template<class T>
AMI_err AMI_STREAM<T>::write_item(const T &elt) {

  assert(fp);
  //if we go past substream range
  if ((logical_eos >= 0) && G_ftell(fp) >= sizeof(T) * logical_eos) {
    return AMI_ERROR_END_OF_STREAM;
  
  } else {
    if (fwrite((char*)(&elt), sizeof(T), 1,fp) < 1) {
      cerr << "ERROR: AMI_STREAM::write_item failed.\n";
      if (path && *path)
	perror(path);
      else
	perror("AMI_STREAM::write_item: ");
      DEBUG_ASSERT assert(0);
      exit(1);
    }

    return AMI_ERROR_NO_ERROR;
  }
};


/**********************************************************************/
template<class T>
AMI_err AMI_STREAM<T>::write_array(const T *data, off_t len) {
  size_t nobj;

  assert(fp);
  //if we go past substream range
  if ((logical_eos >= 0) && G_ftell(fp) >= sizeof(T) * logical_eos) {
    return AMI_ERROR_END_OF_STREAM;
    
  } else {
    nobj = fwrite(data, sizeof(T), len, fp);
    if (nobj  < len) {
      cerr << "ERROR: AMI_STREAM::write_array failed.\n";
      if (path && *path)
	perror(path);
      else
	perror("AMI_STREAM::write_array: ");
      DEBUG_ASSERT assert(0);
      exit(1);
    }
   return AMI_ERROR_NO_ERROR;
  }
};
        

/**********************************************************************/
template<class T>
void AMI_STREAM<T>::persist(persistence p)  {
  per = p;
};



/**********************************************************************/
// sprint()
// Return a string describing the stream
//
// This function gives easy access to the file name, length.
// It is not reentrant, but this should not be too much of a problem 
// if you are careful.
template<class T>
char *AMI_STREAM<T>::sprint()  {
  static char buf[BUFSIZ];
  sprintf(buf, "[AMI_STREAM %s %ld]", path, (long)stream_len());
  return buf;
};

/**********************************************************************/
template<class T>
int AMI_STREAM<T>::eof()  {
  return eof_reached;
};


#endif // _AMI_STREAM_H