Subversion Repositories shark

Rev

Rev 2 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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