OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [umsdos/] [emd.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  linux/fs/umsdos/emd.c
3
 *
4
 *  Written 1993 by Jacques Gelinas
5
 *
6
 *  Extended MS-DOS directory handling functions
7
 */
8
 
9
#include <linux/types.h>
10
#include <linux/fcntl.h>
11
#include <linux/kernel.h>
12
#include <linux/sched.h>
13
#include <linux/errno.h>
14
#include <linux/string.h>
15
#include <linux/msdos_fs.h>
16
#include <linux/umsdos_fs.h>
17
 
18
#include <asm/segment.h>
19
 
20
#define PRINTK(x)
21
#define Printk(x) printk x
22
 
23
/*
24
        Read a file into kernel space memory
25
*/
26
int umsdos_file_read_kmem(
27
        struct inode *inode,
28
        struct file *filp,
29
        char *buf,
30
        int count)
31
{
32
        int ret;
33
        int old_fs = get_fs();
34
        set_fs (KERNEL_DS);
35
        ret = fat_file_read(inode,filp,buf,count);
36
        set_fs (old_fs);
37
        return ret;
38
}
39
/*
40
        Write to a file from kernel space
41
*/
42
int umsdos_file_write_kmem(
43
        struct inode *inode,
44
        struct file *filp,
45
        const char *buf,
46
        int count)
47
{
48
        int ret;
49
        int old_fs = get_fs();
50
        set_fs (KERNEL_DS);
51
        ret = fat_file_write(inode,filp,buf,count);
52
        set_fs (old_fs);
53
        return ret;
54
}
55
 
56
 
57
/*
58
        Write a block of bytes into one EMD file.
59
        The block of data is NOT in user space.
60
 
61
        Return 0 if ok, a negative error code if not.
62
*/
63
int umsdos_emd_dir_write (
64
        struct inode *emd_dir,
65
        struct file *filp,
66
        char *buf,      /* buffer in kernel memory, not in user space */
67
        int count)
68
{
69
        int written;
70
        filp->f_flags = 0;
71
        written = umsdos_file_write_kmem (emd_dir,filp,buf,count);
72
        return written != count ? -EIO : 0;
73
}
74
/*
75
        Read a block of bytes from one EMD file.
76
        The block of data is NOT in user space.
77
        Return 0 if ok, -EIO if any error.
78
*/
79
int umsdos_emd_dir_read (
80
        struct inode *emd_dir,
81
        struct file *filp,
82
        char *buf,      /* buffer in kernel memory, not in user space */
83
        int count)
84
{
85
        int ret = 0;
86
        int sizeread;
87
        filp->f_flags = 0;
88
        sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count);
89
        if (sizeread != count){
90
                printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n"
91
                        ,filp->f_pos,sizeread,count);
92
                ret = -EIO;
93
        }
94
        return ret;
95
 
96
}
97
/*
98
        Locate the EMD file in a directory and optionally, creates it.
99
 
100
        Return NULL if error. If ok, dir->u.umsdos_i.emd_inode
101
*/
102
struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat)
103
{
104
        struct inode *ret = NULL;
105
        if (dir->u.umsdos_i.i_emd_dir != 0){
106
                ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
107
                PRINTK (("deja trouve %d %x [%ld] "
108
                        ,dir->u.umsdos_i.i_emd_dir,ret,ret->i_count));
109
        }else{
110
                umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret);
111
                PRINTK (("emd_dir_lookup "));
112
                if (ret != NULL){
113
                        PRINTK (("Find --linux "));
114
                        dir->u.umsdos_i.i_emd_dir = ret->i_ino;
115
                }else if (creat){
116
                        int code;
117
                        PRINTK (("avant create "));
118
                        dir->i_count++;
119
                        code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
120
                                ,S_IFREG|0777,&ret);
121
                        PRINTK (("Creat EMD code %d ret %x ",code,ret));
122
                        if (ret != NULL){
123
                                dir->u.umsdos_i.i_emd_dir = ret->i_ino;
124
                        }else{
125
                                printk ("UMSDOS: Can't create EMD file\n");
126
                        }
127
                }
128
        }
129
        if (ret != NULL){
130
                /* Disable UMSDOS_notify_change() for EMD file */
131
                ret->u.umsdos_i.i_emd_owner = 0xffffffff;
132
        }
133
        return ret;
134
}
135
 
136
/*
137
        Read an entry from the EMD file.
138
        Support variable length record.
139
        Return -EIO if error, 0 if ok.
140
*/
141
int umsdos_emd_dir_readentry (
142
        struct inode *emd_dir,
143
        struct file *filp,
144
        struct umsdos_dirent *entry)
145
{
146
        int ret = umsdos_emd_dir_read(emd_dir,filp,(char*)entry,UMSDOS_REC_SIZE);
147
        if (ret == 0){
148
                /* Variable size record. Maybe, we have to read some more */
149
                int recsize = umsdos_evalrecsize (entry->name_len);
150
                if (recsize > UMSDOS_REC_SIZE){
151
                        ret = umsdos_emd_dir_read(emd_dir,filp
152
                                ,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE);
153
 
154
                }
155
        }
156
        return ret;
157
}
158
/*
159
        Write an entry in the EMD file.
160
        Return 0 if ok, -EIO if some error.
161
*/
162
int umsdos_writeentry (
163
        struct inode *dir,
164
        struct inode *emd_dir,
165
        struct umsdos_info *info,
166
        int free_entry)         /* This entry is deleted, so Write all 0's */
167
{
168
        int ret = 0;
169
        struct file filp;
170
        struct umsdos_dirent *entry = &info->entry;
171
        struct umsdos_dirent entry0;
172
        if (free_entry){
173
                /* #Specification: EMD file / empty entries
174
                        Unused entry in the EMD file are identify
175
                        by the name_len field equal to 0. However to
176
                        help future extension (or bug correction :-( ),
177
                        empty entries are filled with 0.
178
                */
179
                memset (&entry0,0,sizeof(entry0));
180
                entry = &entry0;
181
        }else if (entry->name_len > 0){
182
                memset (entry->name+entry->name_len,'\0'
183
                        ,sizeof(entry->name)-entry->name_len);
184
                /* #Specification: EMD file / spare bytes
185
                        10 bytes are unused in each record of the EMD. They
186
                        are set to 0 all the time. So it will be possible
187
                        to do new stuff and rely on the state of those
188
                        bytes in old EMD file around.
189
                */
190
                memset (entry->spare,0,sizeof(entry->spare));
191
        }
192
        filp.f_pos = info->f_pos;
193
        filp.f_reada = 0;
194
        ret = umsdos_emd_dir_write(emd_dir,&filp,(char*)entry,info->recsize);
195
        if (ret != 0){
196
                printk ("UMSDOS: problem with EMD file. Can't write\n");
197
        }else{
198
                dir->i_ctime = dir->i_mtime = CURRENT_TIME;
199
                dir->i_dirt = 1;
200
        }
201
        return ret;
202
}
203
 
204
#define CHUNK_SIZE (8*UMSDOS_REC_SIZE)
205
struct find_buffer{
206
        char buffer[CHUNK_SIZE];
207
        int pos;        /* read offset in buffer */
208
        int size;       /* Current size of buffer */
209
        struct file filp;
210
};
211
 
212
/*
213
        Fill the read buffer and take care of the byte remaining inside.
214
        Unread bytes are simply move to the beginning.
215
 
216
        Return -ENOENT if EOF, 0 if ok, a negative error code if any problem.
217
*/
218
static int umsdos_fillbuf (
219
        struct inode *inode,
220
        struct find_buffer *buf)
221
{
222
        int ret = -ENOENT;
223
        int mustmove = buf->size - buf->pos;
224
        int mustread;
225
        int remain;
226
        if (mustmove > 0){
227
                memcpy (buf->buffer,buf->buffer+buf->pos,mustmove);
228
        }
229
        buf->pos = 0;
230
        mustread = CHUNK_SIZE - mustmove;
231
        remain = inode->i_size - buf->filp.f_pos;
232
        if (remain < mustread) mustread = remain;
233
        if (mustread > 0){
234
                ret = umsdos_emd_dir_read (inode,&buf->filp,buf->buffer+mustmove
235
                        ,mustread);
236
                if (ret == 0) buf->size = mustmove + mustread;
237
        }else if (mustmove){
238
                buf->size = mustmove;
239
                ret = 0;
240
        }
241
        return ret;
242
}
243
 
244
/*
245
        General search, locate a name in the EMD file or an empty slot to
246
        store it. if info->entry.name_len == 0, search the first empty
247
        slot (of the proper size).
248
 
249
        Caller must do iput on *pt_emd_dir.
250
 
251
        Return 0 if found, -ENOENT if not found, another error code if
252
        other problem.
253
 
254
        So this routine is used to either find an existing entry or to
255
        create a new one, while making sure it is a new one. After you
256
        get -ENOENT, you make sure the entry is stuffed correctly and
257
        call umsdos_writeentry().
258
 
259
        To delete an entry, you find it, zero out the entry (memset)
260
        and call umsdos_writeentry().
261
 
262
        All this to say that umsdos_writeentry must be call after this
263
        function since it rely on the f_pos field of info.
264
*/
265
static int umsdos_find (
266
        struct inode *dir,
267
        struct umsdos_info *info,               /* Hold name and name_len */
268
                                                                        /* Will hold the entry found */
269
        struct inode **pt_emd_dir)              /* Will hold the emd_dir inode */
270
                                                                        /* or NULL if not found */
271
{
272
        /* #Specification: EMD file structure
273
                The EMD file uses a fairly simple layout. It is made of records
274
                (UMSDOS_REC_SIZE == 64). When a name can't be written is a single
275
                record, multiple contiguous record are allocated.
276
        */
277
        int ret = -ENOENT;
278
        struct inode *emd_dir = umsdos_emd_dir_lookup(dir,1);
279
        if (emd_dir != NULL){
280
                struct umsdos_dirent *entry = &info->entry;
281
                int recsize = info->recsize;
282
                struct {
283
                        off_t posok;    /* Position available to store the entry */
284
                        int found;              /* A valid empty position has been found */
285
                        off_t one;              /* One empty position -> maybe <- large enough */
286
                        int onesize;    /* size of empty region starting at one */
287
                }empty;
288
                /* Read several entries at a time to speed up the search */
289
                struct find_buffer buf;
290
                buf.pos = 0;
291
                buf.size = 0;
292
                buf.filp.f_pos = 0;
293
                buf.filp.f_reada = 1;
294
                empty.found = 0;
295
                empty.posok = emd_dir->i_size;
296
                empty.onesize = 0;
297
                while (1){
298
                        struct umsdos_dirent *rentry = (struct umsdos_dirent*)
299
                                (buf.buffer + buf.pos);
300
                        int file_pos = buf.filp.f_pos - buf.size + buf.pos;
301
                        if (buf.pos == buf.size){
302
                                ret = umsdos_fillbuf (emd_dir,&buf);
303
                                if (ret < 0){
304
                                        /* Not found, so note where it can be added */
305
                                        info->f_pos = empty.posok;
306
                                        break;
307
                                }
308
                        }else if (rentry->name_len == 0){
309
                                /* We are looking for an empty section at least */
310
                                /* recsize large */
311
                                if (entry->name_len == 0){
312
                                        info->f_pos = file_pos;
313
                                        ret = 0;
314
                                        break;
315
                                }else if (!empty.found){
316
                                        if (empty.onesize == 0){
317
                                                /* This is the first empty record of a section */
318
                                                empty.one = file_pos;
319
                                        }
320
                                        /* grow the empty section */
321
                                        empty.onesize += UMSDOS_REC_SIZE;
322
                                        if (empty.onesize == recsize){
323
                                                /* here is a large enough section */
324
                                                empty.posok = empty.one;
325
                                                empty.found = 1;
326
                                        }
327
                                }
328
                                buf.pos += UMSDOS_REC_SIZE;
329
                        }else{
330
                                int entry_size = umsdos_evalrecsize(rentry->name_len);
331
                                if (buf.pos+entry_size > buf.size){
332
                                        ret = umsdos_fillbuf (emd_dir,&buf);
333
                                        if (ret < 0){
334
                                                /* Not found, so note where it can be added */
335
                                                info->f_pos = empty.posok;
336
                                                break;
337
                                        }
338
                                }else{
339
                                        empty.onesize = 0;       /* Reset the free slot search */
340
                                        if (entry->name_len == rentry->name_len
341
                                                && memcmp(entry->name,rentry->name,rentry->name_len)
342
                                                        ==0){
343
                                                info->f_pos = file_pos;
344
                                                *entry = *rentry;
345
                                                ret = 0;
346
                                                break;
347
                                        }else{
348
                                                buf.pos += entry_size;
349
                                        }
350
                                }
351
                        }
352
                }
353
                umsdos_manglename(info);
354
        }
355
        *pt_emd_dir = emd_dir;
356
        return ret;
357
}
358
/*
359
        Add a new entry in the emd file
360
        Return 0 if ok or a negative error code.
361
        Return -EEXIST if the entry already exist.
362
 
363
        Complete the information missing in info.
364
*/
365
int umsdos_newentry (
366
        struct inode *dir,
367
        struct umsdos_info *info)
368
{
369
        struct inode *emd_dir;
370
        int ret = umsdos_find (dir,info,&emd_dir);
371
        if (ret == 0){
372
                ret = -EEXIST;
373
        }else if (ret == -ENOENT){
374
                ret = umsdos_writeentry(dir,emd_dir,info,0);
375
                PRINTK (("umsdos_newentry EDM ret = %d\n",ret));
376
        }
377
        iput (emd_dir);
378
        return ret;
379
}
380
/*
381
        Create a new hidden link.
382
        Return 0 if ok, an error code if not.
383
*/
384
int umsdos_newhidden (
385
        struct inode *dir,
386
        struct umsdos_info *info)
387
{
388
        struct inode *emd_dir;
389
        int ret;
390
        umsdos_parse ("..LINK",6,info);
391
        info->entry.name_len = 0;
392
        ret = umsdos_find (dir,info,&emd_dir);
393
        iput (emd_dir);
394
        if (ret == -ENOENT || ret == 0){
395
                /* #Specification: hard link / hidden name
396
                        When a hard link is created, the original file is renamed
397
                        to a hidden name. The name is "..LINKNNN" where NNN is a
398
                        number define from the entry offset in the EMD file.
399
                */
400
                info->entry.name_len = sprintf (info->entry.name,"..LINK%ld"
401
                        ,info->f_pos);
402
                ret = 0;
403
        }
404
        return ret;
405
}
406
/*
407
        Remove an entry from the emd file
408
        Return 0 if ok, a negative error code otherwise.
409
 
410
        Complete the information missing in info.
411
*/
412
int umsdos_delentry (
413
        struct inode *dir,
414
        struct umsdos_info *info,
415
        int isdir)
416
{
417
        struct inode *emd_dir;
418
        int ret = umsdos_find (dir,info,&emd_dir);
419
        if (ret == 0){
420
                if (info->entry.name_len != 0){
421
                        if ((isdir != 0) != (S_ISDIR(info->entry.mode) != 0)){
422
                                if (S_ISDIR(info->entry.mode)){
423
                                        ret = -EISDIR;
424
                                }else{
425
                                        ret = -ENOTDIR;
426
                                }
427
                        }else{
428
                                ret = umsdos_writeentry(dir,emd_dir,info,1);
429
                        }
430
                }
431
        }
432
        iput(emd_dir);
433
        return ret;
434
}
435
 
436
 
437
/*
438
        Verify is a EMD directory is empty.
439
        Return 0 if not empty
440
                   1 if empty
441
                   2 if empty, no EMD file.
442
*/
443
int umsdos_isempty (struct inode *dir)
444
{
445
        int ret = 2;
446
        struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
447
        /* If the EMD file does not exist, it is certainly empty :-) */
448
        if (emd_dir != NULL){
449
                struct file filp;
450
                /* Find an empty slot */
451
                filp.f_pos = 0;
452
                filp.f_reada = 1;
453
                filp.f_flags = O_RDONLY;
454
                ret = 1;
455
                while (filp.f_pos < emd_dir->i_size){
456
                        struct umsdos_dirent entry;
457
                        if (umsdos_emd_dir_readentry(emd_dir,&filp,&entry)!=0){
458
                                ret = 0;
459
                                break;
460
                        }else if (entry.name_len != 0){
461
                                ret = 0;
462
                                break;
463
                        }
464
                }
465
                iput (emd_dir);
466
        }
467
        return ret;
468
}
469
 
470
/*
471
        Locate an entry in a EMD directory.
472
        Return 0 if ok, errcod if not, generally -ENOENT.
473
*/
474
int umsdos_findentry (
475
        struct inode *dir,
476
        struct umsdos_info *info,
477
        int expect)             /* 0: anything */
478
                                        /* 1: file */
479
                                        /* 2: directory */
480
{
481
        struct inode *emd_dir;
482
        int ret = umsdos_find (dir,info,&emd_dir);
483
        if (ret == 0){
484
                if (expect != 0){
485
                        if (S_ISDIR(info->entry.mode)){
486
                                if (expect != 2) ret = -EISDIR;
487
                        }else if (expect == 2){
488
                                ret = -ENOTDIR;
489
                        }
490
                }
491
        }
492
        iput (emd_dir);
493
        return ret;
494
}
495
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.