Subversion Repositories shark

Rev

Rev 1063 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1063 tullio 1
 
2 pj 2
/*
1063 tullio 3
 * This program is free software; you can redistribute it and/or modify
4
 * it under the terms of the GNU General Public License as published by
5
 * the Free Software Foundation; either version 2 of the License, or
6
 * (at your option) any later version.
2 pj 7
 *
1063 tullio 8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 * GNU General Public License for more details.
2 pj 12
 *
1063 tullio 13
 * You should have received a copy of the GNU General Public License
14
 * along with this program; if not, write to the Free Software
15
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2 pj 16
 *
17
 */
18
 
1063 tullio 19
 
2 pj 20
#include <fs/maccess.h>
21
#include <fs/util.h>
22
#include <fs/errno.h>
23
#include <fs/stat.h>
24
#include <fs/dirent.h>
25
#include <fs/fcntl.h>
26
 
27
#include "dcache.h"
28
#include "fs.h"
29
#include "msdos.h"
30
#include "fsconst.h"
31
 
32
#include "file.h"
33
#include "fileop.h"
34
#include "msdos/msdos_f.h"
35
 
36
#include "debug.h"
37
 
38
/* debug __position() */
39
#define DEBUG_POSITION KERN_DEBUG
40
#undef DEBUG_POSITION
41
 
42
/* debug __increase() */
43
#define DEBUG_INCREASE KERN_DEBUG
44
#undef DEBUG_INCREASE
45
 
46
/*
47
 *
48
 */
49
 
50
#ifdef DEBUG_POSITION
51
#define printk3a(fmt,args...) \
52
        if (debug_info) printk(DEBUG_POSITION fmt,##args)
53
#else
54
#define printk3a(fmt,args...)
55
#endif
56
 
57
#ifdef DEBUG_INCREASE
58
#define _printk1(fmt,args...) \
59
        if (debug_info) printk(DEBUG_INCREASE fmt,##args)
60
#else
61
#define _printk1(fmt,args...)
62
#endif
63
 
64
static inline void startoffile(struct inode *in, struct file *f)
65
{
66
  MSDOS_F(f).cluster=MSDOS_I(in).scluster;
67
  MSDOS_F(f).bakcluster=NO_CLUSTER;
68
  MSDOS_F(f).lsector=msdos_cluster2sector(in,MSDOS_F(f).cluster);
69
  if (MSDOS_F(f).cluster!=FREE_CLUSTER)
70
    _assert(MSDOS_F(f).lsector!=(__uint32_t)-1);
71
  MSDOS_F(f).sectnum=0;
72
  MSDOS_F(f).bpos=0;
73
}
74
 
75
/*
76
 *
77
 *
78
 */
79
 
80
static int msdos_open(struct inode *in, struct file *f)
81
{
82
  startoffile(in,f);
83
  f->f_pos=0;
84
  printk0("msdos_open: starting (cluster 0x%lx) (lsect %li)",
85
          (long)MSDOS_I(in).scluster,
86
          (long)MSDOS_F(f).lsector);
87
  return EOK;
88
}
89
 
90
static void __position(struct file *f,__off_t pos)
91
{
92
  struct inode *in=f->f_dentry->d_inode;
93
  struct super_block *sb=f->f_dentry->d_sb;
94
  __uint32_t nc;
95
 
96
  /* it can be optimized:
97
   * if the new position is after the actual position we
98
   * can not go thought all the file list chain
99
   */
100
 
101
  /* from 0 (start-of-file) to in->i_st.st_size (end-of-file) */
102
  _assert(pos>=0&&pos<=in->i_st.st_size);
103
 
104
  /* remeber that f->f_pos is the position (in bytes) of the next
105
   * bytes to read/write
106
   * so
107
   * if we are at end-of-file the bytes is not into the file
108
   */
109
 
110
  printk3a("__position: START");
111
 
112
  f->f_pos=pos;
113
  startoffile(in,f);
114
 
115
  nc=pos/(MSDOS_SB(sb).spc*SECTORSIZE);  /* number of cluster to skip */
116
  pos-=nc*(MSDOS_SB(sb).spc*SECTORSIZE);
117
  printk3a("__position: cluster to skip %li",(long)nc);
118
  printk3a("__position: position into cluster %li",(long)pos);
119
 
120
  /* very good :-( I must go thought the list chain! */
121
  while (nc>0) {
122
    MSDOS_F(f).bakcluster=MSDOS_F(f).cluster;
123
    MSDOS_F(f).cluster=msdos_nextcluster(sb,MSDOS_F(f).cluster);
124
    nc--;
125
  }
126
 
127
  MSDOS_F(f).sectnum=pos/SECTORSIZE;
128
  pos-=MSDOS_F(f).sectnum*SECTORSIZE;
129
  printk3a("__position: sector number %i",MSDOS_F(f).sectnum);
130
 
131
  MSDOS_F(f).lsector=msdos_cluster2sector(in,MSDOS_F(f).cluster);
132
  _assert(MSDOS_F(f).lsector!=(__uint32_t)-1);
133
  MSDOS_F(f).lsector+=MSDOS_F(f).sectnum;
134
 
135
  MSDOS_F(f).bpos=pos;
136
  printk3a("__position: position into sector %li",(long)pos);
137
  printk3a("__position: logical sector %li",(long)MSDOS_F(f).lsector);
138
 
139
  printk3a("__position: END");
140
}
141
 
142
static __off_t msdos_lseek(struct file *f, __off_t off, int whence)
143
{
144
  struct inode *in=f->f_dentry->d_inode;
145
  __off_t   pos;
146
 
147
  /* da fare il test sulla fine cluster!!!! */
148
 
149
  printk3("msdos_lseek: START");
150
 
151
  printk3("msdos_lseek: current position %li",(long)f->f_pos);  
152
  switch (whence) {
153
    case SEEK_SET: pos=off; break;
154
    case SEEK_CUR: pos=f->f_pos+off; break;
155
    case SEEK_END: pos=in->i_st.st_size+off; break;
156
    default:
157
      printk3("msdos_lseek: END");
158
      return -EINVAL;
159
  }
160
  printk3("msdos_lseek: next position %li",(long)pos);
161
 
162
  if (pos<0) {
163
    printk3("msdos_lseek: out of position range");
164
    printk3("msdos_lseek: END");
165
    return -ESPIPE; /* it is "illegal seek" */
166
  }
167
 
168
  f->f_pos=pos;
169
 
170
  if (f->f_pos>in->i_st.st_size) {
171
    printk3("msdos_lseek: after end-of-file");
172
    printk3("msdos_lseek: END");
173
    return f->f_pos;
174
  }
175
 
176
  __position(f,pos);
177
 
178
  printk3("msdos_lseek: END");
179
  return f->f_pos;  
180
}
181
 
182
static int msdos_close(struct inode *in, struct file *f)
183
{
184
  return EOK;
185
}
186
 
187
/* --- */
188
 
189
/* advance the file pointer by sz bytes */
190
/* PS: sz must NOT cross sectors (see msdos_read())*/
191
static void __inline__ __advance(struct file *f,
192
                               struct super_block *sb,
193
                               struct inode *in,
194
                               int sz)
195
{
196
  f->f_pos+=sz;
197
  if (sz==SECTORSIZE-MSDOS_F(f).bpos) {
198
    MSDOS_F(f).bpos=0;
199
    MSDOS_F(f).lsector++;
200
    MSDOS_F(f).sectnum++;
201
 
202
    if (MSDOS_I(in).scluster==ROOT_CLUSTER) return;
203
 
204
    if (MSDOS_F(f).sectnum==MSDOS_SB(sb).spc) {
205
      MSDOS_F(f).sectnum=0;
206
 
207
      //printk(KERN_DEBUG "act cluster 0x%04li",(long)MSDOS_F(f).cluster);
208
 
209
      MSDOS_F(f).bakcluster=MSDOS_F(f).cluster;
210
      MSDOS_F(f).cluster=msdos_nextcluster(sb,MSDOS_F(f).cluster);
211
      if (MSDOS_F(f).cluster!=NO_CLUSTER) {
212
        MSDOS_F(f).lsector=msdos_cluster2sector(in,MSDOS_F(f).cluster);
213
        _assert(MSDOS_F(f).lsector!=(__uint32_t)-1);
214
      }
215
 
216
      //printk(KERN_DEBUG "new cluster 0x%04li",(long)MSDOS_F(f).cluster);
217
 
218
    }
219
  } else {
220
    MSDOS_F(f).bpos+=sz;
221
  }
222
}
223
 
224
/* increase the file size by delta (we must be on end-of-file) */
225
static __ssize_t __inline__ __increase(struct file *f,
226
                               struct super_block *sb,
227
                               struct inode *in,
228
                               __ssize_t delta)
229
{
230
  __uint16_t scluster,cluster;
231
  __ssize_t l;
232
  long i,n;
233
 
234
  _printk1("__increase: START");
235
  _printk1("__increase: clusters act:0x%04x bak:0x%04x",
236
           MSDOS_F(f).cluster,MSDOS_F(f).bakcluster);
237
 
238
  /*
239
   * MSDOS_F(f).bakcluster contains the previous cluster of the actual
240
   * file position;
241
   * it is used only into when MSDOS_F(f).cluster==NO_CLUSTER
242
   * (we are at end-of-file of a file that is multiple of a cluster)
243
   */
244
 
245
  _assert(delta!=0);
246
  if (MSDOS_I(in).scluster==ROOT_CLUSTER) return 0;
247
 
248
  if (MSDOS_F(f).cluster==FREE_CLUSTER) {
249
    /* we must allocate a cluster */
250
    /* we do not have any cluster in this chain! */
251
    _printk1("__increase: free cluster");
252
    MSDOS_F(f).cluster=msdos_addcluster(sb,NO_CLUSTER);
253
    if (MSDOS_F(f).cluster==NO_CLUSTER) return 0;
254
    MSDOS_F(f).lsector=msdos_cluster2sector(in,MSDOS_F(f).cluster);    
255
    _assert(MSDOS_F(f).lsector!=(__uint32_t)-1);
256
    MSDOS_I(in).scluster=MSDOS_F(f).cluster;
257
    in->i_dirty=1;
258
  }
259
 
260
  if (MSDOS_F(f).cluster==NO_CLUSTER) {
261
    /* we must allocate a cluster */
262
    /* we are at end-of-file on a cluster boundary! */
263
    _printk1("__increase: no cluster");    
264
    _assert(MSDOS_F(f).bakcluster!=NO_CLUSTER);
265
    MSDOS_F(f).cluster=msdos_addcluster(sb,MSDOS_F(f).bakcluster);
266
    if (MSDOS_F(f).cluster==NO_CLUSTER) return 0;
267
    MSDOS_F(f).lsector=msdos_cluster2sector(in,MSDOS_F(f).cluster);
268
    _assert(MSDOS_F(f).lsector!=(__uint32_t)-1);
269
  }
270
 
271
  _printk1("__increase: compute space available");
272
 
273
  /* space available (to the end of cluster) */
274
  l=((__ssize_t)MSDOS_SB(sb).spc-(__ssize_t)MSDOS_F(f).sectnum-1)*SECTORSIZE;
275
  l+=(SECTORSIZE-(__ssize_t)MSDOS_F(f).bpos);
276
 
277
  if ((long)delta-(long)l>0) {
278
    /* some other clusters needed */
279
    n=(delta-l)/(SECTORSIZE*MSDOS_SB(sb).spc)+1;
280
    scluster=cluster=MSDOS_F(f).cluster;
281
 
282
    _printk1("__increase: other clusters needed");
283
 
284
    for (i=0;i<n;i++) {
285
      _printk1("__increase: added cluster from 0x%04x",cluster);
286
      cluster=msdos_addcluster(sb,cluster);
287
      if (cluster==NO_CLUSTER) {
288
        /* we shall allow an allocation lesser than requested */
289
        delta=l+i*SECTORSIZE*MSDOS_SB(sb).spc;
290
        break;
291
      }
292
    }
293
 
294
  }
295
 
296
  if (delta>0) {
297
    _printk1("__increase: delta>0 => dirty inode");    
298
    in->i_st.st_size+=delta;
299
    in->i_dirty=1;
300
  }
301
  _printk1("__increase: END");
302
  return delta;
303
}
304
 
305
/*
306
 *
307
 */
308
 
309
static __ssize_t msdos_read(struct file *f, char *p, __ssize_t d)
310
{
311
  struct inode *in=f->f_dentry->d_inode;
312
  struct super_block *sb=f->f_dentry->d_sb;
313
  dcache_t *buf;
314
  int sz;
315
  __ssize_t bc;
316
 
317
  //printk(KERN_DEBUG "reading %i bytes from position %li",d,(long)f->f_pos);
318
 
319
  if (d==0) return 0;
320
 
321
  /* if we are at or after the end-of-file */
322
  if (f->f_pos>=in->i_st.st_size) return 0;
323
 
324
  bc=0;
325
  while (bc<d&&in->i_st.st_size>f->f_pos) {
326
    buf=dcache_lock(sb->sb_dev,MSDOS_F(f).lsector);
327
    if (buf==NULL) return -EIO;
328
    sz=min(d-bc,SECTORSIZE-MSDOS_F(f).bpos);
329
    sz=min(sz,in->i_st.st_size-f->f_pos);
330
    memcpytouser(p,buf->buffer+MSDOS_F(f).bpos,sz);
331
    dcache_unlock(buf);
332
    p+=sz;    
333
    bc+=sz;
334
    __advance(f,sb,in,sz);    
335
  }
336
 
337
  return bc;
338
}
339
 
340
static __ssize_t msdos_write(struct file *f, char *p, __ssize_t d)
341
{
342
  struct inode *in=f->f_dentry->d_inode;
343
  struct super_block *sb=f->f_dentry->d_sb;
344
  dcache_t *buf;
345
  int sz;
346
  __ssize_t bc;
347
 
348
  //printk(KERN_DEBUG "writing %i bytes from position %li",d,(long)f->f_pos);
349
 
350
  if (d==0) return 0;
351
 
352
  /* O_APPEND flag - test for safety */
353
  /*
354
  if (f->f_flags&O_APPEND)
355
    if (f->f_pos!=in->i_st.st_size) {
356
      __position(f,in->i_st.st_size);      
357
    }
358
  */
359
 
360
  if (f->f_pos>in->i_st.st_size) {
361
    /* lseek() has moved the file position AFTER the end of file !!*/
362
 
363
    __ssize_t inc,delta;
364
 
365
    //printk(KERN_DEBUG "lseek() after end of file!");
366
 
367
    delta=f->f_pos-in->i_st.st_size;
368
    __position(f,in->i_st.st_size);
369
    inc=__increase(f,sb,in,delta);
370
    if (inc!=delta) return -EIO;
371
 
372
    bc=0;
373
    while (bc<delta) {
374
      buf=dcache_acquire(sb->sb_dev,MSDOS_F(f).lsector);    
375
      if (buf==NULL) return -EIO;
376
      dcache_dirty(buf);
377
      sz=min(delta-bc,SECTORSIZE-MSDOS_F(f).bpos);
378
      sz=min(sz,in->i_st.st_size-f->f_pos);
379
      memset(buf->buffer+MSDOS_F(f).bpos,0,sz);
380
      dcache_release(buf);
381
      bc+=sz;
382
      __advance(f,sb,in,sz);    
383
    }
384
 
385
  }
386
 
387
  /*
388
  printk(KERN_DEBUG "pos: %li d: %li act size: %li",
389
         (long)f->f_pos,(long)d,(long)in->i_st.st_size);
390
  */
391
 
392
  if (f->f_pos+d>in->i_st.st_size) {
393
    /* no room for the data that must be written */
394
    __ssize_t inc;
395
 
396
    //printk(KERN_DEBUG "increase request" );
397
 
398
    inc=__increase(f,sb,in,f->f_pos+d-in->i_st.st_size);
399
    if (inc==0) return -EIO;
400
    d=inc+in->i_st.st_size-f->f_pos;
401
 
402
    //printk(KERN_DEBUG "new size: %li",(long)in->i_st.st_size);
403
  }
404
 
405
  //printk(KERN_DEBUG "init writing");
406
 
407
  bc=0;
408
  while (bc<d&&in->i_st.st_size>f->f_pos) {
409
    buf=dcache_acquire(sb->sb_dev,MSDOS_F(f).lsector);
410
    if (buf==NULL) {
411
      //printk(KERN_DEBUG "can't aquire!");
412
      return -EIO;
413
    }    
414
    //printk(KERN_DEBUG "write on %li",MSDOS_F(f).lsector);        
415
    dcache_dirty(buf);
416
    sz=min(d-bc,SECTORSIZE-MSDOS_F(f).bpos);
417
    sz=min(sz,in->i_st.st_size-f->f_pos);
418
    memcpyfromuser(buf->buffer+MSDOS_F(f).bpos,p,sz);
419
    dcache_release(buf);
420
    p+=sz;    
421
    bc+=sz;
422
    __advance(f,sb,in,sz);    
423
  }
424
 
425
  return bc;
426
}
427
 
428
#ifdef DEBUG_READDIR_DUMP
429
#define dump_directory_entry(ptr) msdos_dump_direntry(ptr)
430
#else
431
#define dump_directory_entry(ptr)
432
#endif
433
 
434
//int startcounter=0;
435
//int counter;
436
 
437
static int msdos_readdir(struct file *f, void *den)
438
{
439
  struct super_block *sb=f->f_dentry->d_sb;
440
  struct inode *in=f->f_dentry->d_inode;
441
  struct directoryentry *de;
442
  struct dirent ude;
443
  dcache_t *buf=NULL;
444
  struct qstr name;
445
  __uint32_t lsect;
446
  int res;
447
 
448
  //debug_check_mutex(__FILE__,__LINE__,501);
449
 
450
  printk5("msdos_readdir: START");
451
 
452
  if (MSDOS_F(f).cluster==NO_CLUSTER) {
453
    printk5("msdos_readdir: end of cluster (no more entries)");
454
    printk5("msdos_readdir: END");
455
    return 1;
456
  }
457
 
458
  lsect=-1;
459
  for (;;) {
460
 
461
    if (MSDOS_F(f).lsector!=lsect) {
462
      if (lsect!=-1) dcache_unlock(buf);
463
      buf=dcache_lock(sb->sb_dev,MSDOS_F(f).lsector);
464
      if (buf==NULL) {
465
        //printk(KERN_ERR "msdos_readdir: can't lock sector %li",
466
        //       (long)MSDOS_F(f).lsector);
467
        printk5("msdos_readdir: END");
468
        return -EIO;
469
      }
470
      lsect=MSDOS_F(f).lsector;
471
      printk5("msdos_readdir: read %li logical sector",(long int)lsect);
472
    }
473
 
474
    de=(struct directoryentry *)(buf->buffer+MSDOS_F(f).bpos);
475
    dump_directory_entry(de);
476
 
477
    /*
478
      for debug purpose
479
    if (startcounter) {
480
      if (--counter==0) return 1;
481
    } else
482
 
483
    if (msdos_islastentry(de)) {
484
      startcounter=1;
485
      counter=1;
486
    }
487
    */
488
 
489
    if (msdos_islastentry(de)) {
490
      printk5("msdos_readdir: last entry found");
491
      printk5("msdos_readdir: END");
492
      // *(int*)&ude=0;
493
      dcache_unlock(buf);
494
      return 1;      
495
    }
496
 
497
    __advance(f,sb,in,sizeof(struct directoryentry));
498
 
499
    if (!msdos_isunvalidentry(de)) {
500
      res=msdos_formatname(de,&name);
501
 
502
      /* there's no need to check for result, but in future... */      
503
      if (res!=0) {
504
        printk5("msdos_readdir: entry found BUT can't format the name");
505
        printk5("msdos_readdir: END");
506
        dcache_unlock(buf);
507
        return -EIO;
508
      }
509
 
510
      strcpy(ude.d_name,QSTRNAME(&name));
511
      printk5("msdos_readdir: entry found '%s'",ude.d_name);
512
      break;
513
    }
514
    printk5("msdos_readdir: invalid entry found");
515
  }
516
  dcache_unlock(buf);
517
 
518
  __copy_to_user(den,&ude,sizeof(struct dirent));
519
  printk5("msdos_readdir: END");
520
  return EOK;
521
}
522
 
523
 
524
/*--------*/
525
 
526
struct file_operations msdos_file_ro_operations={
527
  msdos_lseek,
528
  msdos_read,
529
  dummy_write,
530
  msdos_readdir,
531
  msdos_open,
532
  msdos_close
533
};
534
 
535
struct file_operations msdos_file_rw_operations={
536
  msdos_lseek,
537
  msdos_read,
538
  msdos_write,
539
  msdos_readdir,
540
  msdos_open,
541
  msdos_close
542
};