home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / mtools_3.6.src.lzh / MTOOLS_3.6 / file.c < prev    next >
C/C++ Source or Header  |  1997-11-12  |  9KB  |  426 lines

  1. #include "sysincludes.h"
  2. #include "msdos.h"
  3. #include "stream.h"
  4. #include "mtools.h"
  5. #include "fsP.h"
  6. #include "file.h"
  7. #include "htable.h"
  8.  
  9. #ifdef _OSK
  10. #ifdef _UCC
  11. #include <os9time.h>
  12. #endif
  13. #endif
  14.  
  15. typedef struct File_t {
  16.     Class_t *Class;
  17.     int refs;
  18.     struct Fs_t *Fs;    /* Filesystem that this fat file belongs to */
  19.     Stream_t *Buffer;
  20.  
  21.     int (*map)(struct File_t *this, off_t where, size_t *len, int mode);
  22.     size_t FileSize;
  23.  
  24.     /* Absolute position of first cluster of file */
  25.     unsigned int FirstAbsCluNr;
  26.  
  27.     /* Absolute position of previous cluster */
  28.     unsigned int PreviousAbsCluNr;
  29.  
  30.     /* Relative position of previous cluster */
  31.     unsigned int PreviousRelCluNr;
  32.     struct directory dir;
  33.     int locked;
  34.     Stream_t *ParentDir;
  35. } File_t;
  36.  
  37. static int normal_map(File_t *This, off_t where, size_t *len, int mode)
  38. {
  39.     int offset;
  40.     int NrClu; /* number of clusters to read */
  41.     unsigned int RelCluNr;
  42.     unsigned int CurCluNr;
  43.     unsigned int NewCluNr;
  44.     unsigned int AbsCluNr;
  45.     int clus_size;
  46.     Fs_t *Fs = This->Fs;
  47.  
  48.     clus_size = Fs->cluster_size * Fs->sector_size;
  49.     offset = where % clus_size;
  50.  
  51.     if (mode == MT_READ)
  52.         maximize(len, This->FileSize - where);
  53.     if (*len == 0 )
  54.         return 0;
  55.  
  56.     if (This->FirstAbsCluNr < 2){
  57.         if( mode == MT_READ || *len == 0){
  58.             *len = 0;
  59.             return 0;
  60.         }
  61.         NewCluNr = get_next_free_cluster(This->Fs, 1);
  62.         if (NewCluNr == 1 ){
  63.             errno = ENOSPC;
  64.             return -2;
  65.         }
  66.         This->FirstAbsCluNr = NewCluNr;
  67.         Fs->fat_encode(This->Fs, NewCluNr, Fs->end_fat);
  68.     }
  69.  
  70.     RelCluNr = where / clus_size;
  71.     
  72.     if (RelCluNr >= This->PreviousRelCluNr){
  73.         CurCluNr = This->PreviousRelCluNr;
  74.         AbsCluNr = This->PreviousAbsCluNr;
  75.     } else {
  76.         CurCluNr = 0;
  77.         AbsCluNr = This->FirstAbsCluNr;
  78.     }
  79.  
  80.  
  81.     NrClu = (offset + *len - 1) / clus_size;
  82.     while (CurCluNr <= RelCluNr + NrClu){
  83.         if (CurCluNr == RelCluNr){
  84.             /* we have reached the beginning of our zone. Save
  85.              * coordinates */
  86.             This->PreviousRelCluNr = RelCluNr;
  87.             This->PreviousAbsCluNr = AbsCluNr;
  88.         }
  89.         NewCluNr = Fs->fat_decode(This->Fs, AbsCluNr);
  90.         if (NewCluNr == 1 ){
  91.             fprintf(stderr,"Fat problem while decoding %d\n", 
  92.                 AbsCluNr);
  93.             exit(1);
  94.         }
  95.         if(CurCluNr == RelCluNr + NrClu)            
  96.             break;
  97.         if (NewCluNr > Fs->last_fat && mode == MT_WRITE){
  98.             /* if at end, and writing, extend it */
  99.             NewCluNr = get_next_free_cluster(This->Fs, AbsCluNr);
  100.             if (NewCluNr == 1 ){ /* no more space */
  101.                 errno = ENOSPC;
  102.                 return -2;
  103.             }
  104.             Fs->fat_encode(This->Fs, AbsCluNr, NewCluNr);
  105.             Fs->fat_encode(This->Fs, NewCluNr, Fs->end_fat);
  106.         }
  107.  
  108.         if (CurCluNr < RelCluNr && NewCluNr > Fs->last_fat){
  109.             *len = 0;
  110.             return 0;
  111.         }
  112.  
  113.         if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
  114.             break;
  115.         CurCluNr++;
  116.         AbsCluNr = NewCluNr;
  117.     }
  118.  
  119.     maximize(len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
  120.  
  121.     return ((This->PreviousAbsCluNr-2) * Fs->cluster_size+Fs->clus_start) *
  122.             Fs->sector_size + offset;
  123. }
  124.  
  125.  
  126. static int root_map(File_t *This, off_t where, size_t *len, int mode)
  127. {
  128.     Fs_t *Fs = This->Fs;
  129.  
  130.     if(Fs->dir_len * Fs->sector_size < where) {
  131.         *len = 0;
  132.         errno = ENOSPC;
  133.         return -2;
  134.     }
  135.  
  136.     maximize(len, Fs->dir_len * Fs->sector_size - where);
  137.     return Fs->dir_start * Fs->sector_size + where;
  138. }
  139.     
  140.  
  141. static int read_file(Stream_t *Stream, char *buf, off_t where, size_t len)
  142. {
  143.     DeclareThis(File_t);
  144.     int pos;
  145.  
  146.     Stream_t *Disk = This->Fs->Next;
  147.     
  148.     pos = This->map(This, where, &len, MT_READ);
  149.     if(pos < 0)
  150.         return pos;
  151.     return READS(Disk, buf, pos, len);
  152. }
  153.  
  154. static int write_file(Stream_t *Stream, char *buf, off_t where, size_t len)
  155. {
  156.     DeclareThis(File_t);
  157.     int pos;
  158.     int ret;
  159.     Stream_t *Disk = This->Fs->Next;
  160.  
  161.     pos = This->map(This, where, &len, MT_WRITE);
  162.     if( pos < 0)
  163.         return pos;
  164.     ret = WRITES(Disk, buf, pos, len);
  165.     if ( ret > 0 && where + ret > This->FileSize )
  166.         This->FileSize = where + ret;
  167.     return ret;
  168. }
  169.  
  170.  
  171. /*
  172.  * Convert an MSDOS time & date stamp to the Unix time() format
  173.  */
  174.  
  175. static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  176. static inline long conv_stamp(struct directory *dir)
  177. {
  178.     struct tm *tmbuf;
  179.     long tzone, dst;
  180.     time_t accum;
  181.  
  182.     accum = DOS_YEAR(dir) - 1970; /* years past */
  183.  
  184.     /* days passed */
  185.     accum = accum * 365L + month[DOS_MONTH(dir)-1] + DOS_DAY(dir);
  186.  
  187.     /* leap years */
  188.     accum += (DOS_YEAR(dir) - 1972) / 4L;
  189.  
  190.     /* back off 1 day if before 29 Feb */
  191.     if (!(DOS_YEAR(dir) % 4) && DOS_MONTH(dir) < 3)
  192.             accum--;
  193.     accum = accum * 24L + DOS_HOUR(dir); /* hours passed */
  194.     accum = accum * 60L + DOS_MINUTE(dir); /* minutes passed */
  195.     accum = accum * 60L + DOS_SEC(dir); /* seconds passed */
  196.  
  197.     /* correct for Time Zone */
  198. #ifdef HAVE_GETTIMEOFDAY
  199.     {
  200.         struct timeval tv;
  201.         struct timezone tz;
  202.         
  203.         gettimeofday(&tv, &tz);
  204.         tzone = tz.tz_minuteswest * 60L;
  205.     }
  206. #else
  207. #ifdef HAVE_TZSET
  208.     {
  209. #ifndef ultrix
  210.         /* Ultrix defines this to be a different type */
  211.         extern long timezone;
  212. #endif
  213.         tzset();
  214.         tzone = (long) timezone;
  215.     }
  216. #else
  217.     tzone = 0;
  218. #endif /* HAVE_TZSET */
  219. #endif /* HAVE_GETTIMEOFDAY */
  220.     
  221.     accum += tzone;
  222.  
  223.     /* correct for Daylight Saving Time */
  224.     tmbuf = localtime(&accum);
  225.     dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L;
  226.     accum += dst;
  227.     
  228.     return accum;
  229. }
  230.  
  231.  
  232. static int get_file_data(Stream_t *Stream, long *date, size_t *size,
  233.              int *type, int *address)
  234. {
  235.     DeclareThis(File_t);
  236.  
  237.     if(date)
  238.         *date = conv_stamp(& This->dir);
  239.     if(size)
  240.         *size = This->FileSize;
  241.     if(type)
  242.         *type = This->dir.attr & 0x10;
  243.     if(address)
  244.         *address = This->FirstAbsCluNr;
  245.     return 0;
  246. }
  247.  
  248. T_HashTable *filehash;
  249.  
  250. static int free_file(Stream_t *Stream)
  251. {
  252.     DeclareThis(File_t);
  253.     FREE(&This->ParentDir);
  254.     return hash_remove(filehash, (void *) Stream, 0);
  255. }
  256.  
  257. static Class_t FileClass = { 
  258.     read_file, 
  259.     write_file, 
  260.     0, /* flush */
  261.     free_file, /* free */
  262.     0, /* get_geom */
  263.     get_file_data 
  264. };
  265.  
  266.  
  267. static unsigned int func1(void *Stream)
  268. {
  269.     DeclareThis(File_t);
  270.  
  271.     return This->FirstAbsCluNr ^ (long) This->Fs;
  272. }
  273.  
  274. static unsigned int func2(void *Stream)
  275. {
  276.     DeclareThis(File_t);
  277.  
  278.     return This->FirstAbsCluNr;
  279. }
  280.  
  281. static int comp(void *Stream, void *Stream2)
  282. {
  283.     DeclareThis(File_t);
  284.  
  285.     File_t *This2 = (File_t *) Stream2;
  286.  
  287.     return This->Fs != This2->Fs ||
  288.         This->FirstAbsCluNr != This2->FirstAbsCluNr;
  289. }
  290.  
  291. static void init_hash(void)
  292. {
  293.     static int is_initialised=0;
  294.     
  295.     if(!is_initialised){
  296.         make_ht(func1, func2, comp, 20, &filehash);
  297.         is_initialised = 1;
  298.     }
  299. }
  300.  
  301.  
  302. static Stream_t *OpenFileByNumAndSize(Stream_t *Dir, unsigned int first, 
  303.                       size_t size, struct directory *dir);
  304.  
  305. Stream_t *open_root(Stream_t *Dir)
  306. {
  307.     Stream_t *Stream = GetFs(Dir);
  308.     DeclareThis(Fs_t);
  309.     File_t *File;
  310.     File_t Pattern;
  311.     unsigned int num;
  312.  
  313.     num = fat32RootCluster(Dir);
  314.  
  315.     if(num)        
  316.         return OpenFileByNumAndSize(Dir, num, MAX_SIZE, 0);
  317.  
  318.     init_hash();
  319.     This->refs++;
  320.     Pattern.Fs = (Fs_t *) This;
  321.     Pattern.FirstAbsCluNr = 0;
  322.     if(!hash_lookup(filehash, (T_HashTableEl) &Pattern, 
  323.             (T_HashTableEl **)&File, 0)){
  324.         File->refs++;
  325.         This->refs--;
  326.         return (Stream_t *) File;
  327.     }
  328.  
  329.     File = New(File_t);
  330.     File->Fs = This;
  331.     if (!File)
  332.         return NULL;
  333.  
  334.     File->ParentDir = 0;
  335.     File->FirstAbsCluNr = 0;    
  336.     File->FileSize = -1;
  337.     File->Class = &FileClass;
  338.     File->map = root_map;
  339.     File->refs = 1;
  340.     File->Buffer = 0;
  341.     hash_add(filehash, (void *) File);
  342.     return (Stream_t *) File;
  343. }
  344.  
  345. Stream_t *open_file(Stream_t *Dir, struct directory *dir)
  346. {
  347.     Stream_t *Stream = GetFs(Dir);
  348.     unsigned int first;
  349.     size_t size;
  350.  
  351.     first = START(dir);
  352.     if(fat32RootCluster(Stream))
  353.         first |= STARTHI(dir) << 16;
  354.  
  355.     if(!first && (dir->attr & 0x10))
  356.         return open_root(Stream);
  357.     
  358.     if (dir->attr & 0x10 )
  359.         size = MAX_SIZE;
  360.     else 
  361.         size = FILE_SIZE(dir);
  362.  
  363.     return OpenFileByNumAndSize(Dir, first, size, dir);
  364. }
  365.  
  366. static Stream_t *OpenFileByNumAndSize(Stream_t *Dir, unsigned int first, 
  367.                       size_t size, struct directory *dir)
  368. {
  369.     Stream_t *Stream = GetFs(Dir);
  370.     DeclareThis(Fs_t);
  371.     File_t Pattern;
  372.     File_t *File;
  373.  
  374.     init_hash();
  375.     This->refs++;
  376.     if(first >= 2){
  377.         /* if we have a zero-addressed file here, it is certainly
  378.          * _not_ the root directory, but rather a newly created
  379.          * file */
  380.         Pattern.Fs = This;
  381.         Pattern.FirstAbsCluNr = first;
  382.         if(!hash_lookup(filehash, (T_HashTableEl) &Pattern, 
  383.                 (T_HashTableEl **)&File, 0)){
  384.             File->refs++;
  385.             This->refs--;
  386.             return (Stream_t *) File;
  387.         }
  388.     }
  389.  
  390.     File = New(File_t);
  391.     if (!File)
  392.         return NULL;
  393.     
  394.     /* memorize dir for date and attrib */
  395.     if(dir)
  396.         File->dir = *dir;
  397.     File->ParentDir = COPY(Dir);
  398.     File->locked = 0;
  399.     File->Class = &FileClass;
  400.     File->Fs = This;
  401.     File->map = normal_map;
  402.     File->FirstAbsCluNr = first;
  403.     File->PreviousRelCluNr = 0xffff;
  404.     File->FileSize = size;
  405.     File->refs = 1;
  406.     File->Buffer = 0;
  407.     hash_add(filehash, (void *) File);
  408.     return (Stream_t *) File;
  409. }
  410.  
  411. int FileIsLocked(Stream_t *Stream)
  412. {
  413.     DeclareThis(File_t);
  414.  
  415.     return This->locked;
  416. }
  417.  
  418. void LockFile(Stream_t *Stream)
  419. {
  420.     DeclareThis(File_t);
  421.  
  422.     This->locked = 1;
  423. }
  424.  
  425.     
  426.