This source file includes following definitions.
- msdos_format_name
- msdos_find
- msdos_lookup
- msdos_create_entry
- msdos_create
- dump_fat
- msdos_mkdir
- msdos_empty
- msdos_rmdir
- msdos_unlinkx
- msdos_unlink
- msdos_unlink_umsdos
- rename_same_dir
- rename_diff_dir
- msdos_rename
1
2
3
4
5
6
7 #ifdef MODULE
8 #include <linux/module.h>
9 #endif
10
11 #include <asm/segment.h>
12
13 #include <linux/sched.h>
14 #include <linux/msdos_fs.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/stat.h>
19
20 #include "msbuffer.h"
21
22 #define PRINTK(x)
23
24
25
26 static char *reserved_names[] = {
27 "CON ","PRN ","NUL ","AUX ",
28 "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
29 "COM1 ","COM2 ","COM3 ","COM4 ",
30 NULL };
31
32
33
34
35 static char bad_chars[] = "*?<>|\"";
36 static char bad_if_strict[] = "+=,; ";
37
38
39
40
41 static int msdos_format_name(char conv,const char *name,int len,char *res,
42 int dot_dirs)
43 {
44 char *walk,**reserved;
45 unsigned char c;
46 int space;
47
48 if (IS_FREE(name)) return -EINVAL;
49 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
50 if (!dot_dirs) return -EEXIST;
51 memset(res+1,' ',10);
52 while (len--) *res++ = '.';
53 return 0;
54 }
55 space = 1;
56 c = 0;
57 for (walk = res; len && walk-res < 8; walk++) {
58 c = *name++;
59 len--;
60 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
61 if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
62 if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
63 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
64 if (c == '.') break;
65 space = c == ' ';
66 *walk = c >= 'a' && c <= 'z' ? c-32 : c;
67 }
68 if (space) return -EINVAL;
69 if (conv == 's' && len && c != '.') {
70 c = *name++;
71 len--;
72 if (c != '.') return -EINVAL;
73 }
74 while (c != '.' && len--) c = *name++;
75 if (c == '.') {
76 while (walk-res < 8) *walk++ = ' ';
77 while (len > 0 && walk-res < MSDOS_NAME) {
78 c = *name++;
79 len--;
80 if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
81 if (conv == 's' && strchr(bad_if_strict,c))
82 return -EINVAL;
83 if (c < ' ' || c == ':' || c == '\\' || c == '.')
84 return -EINVAL;
85 if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
86 space = c == ' ';
87 *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
88 }
89 if (space) return -EINVAL;
90 if (conv == 's' && len) return -EINVAL;
91 }
92 while (walk-res < MSDOS_NAME) *walk++ = ' ';
93 for (reserved = reserved_names; *reserved; reserved++)
94 if (!strncmp(res,*reserved,8)) return -EINVAL;
95 return 0;
96 }
97
98
99
100
101 static int msdos_find(struct inode *dir,const char *name,int len,
102 struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
103 {
104 char msdos_name[MSDOS_NAME];
105 int res;
106
107 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
108 msdos_name,1)) < 0) return res;
109 return msdos_scan(dir,msdos_name,bh,de,ino);
110 }
111
112
113 int msdos_lookup(struct inode *dir,const char *name,int len,
114 struct inode **result)
115 {
116 struct super_block *sb = dir->i_sb;
117 int ino,res;
118 struct msdos_dir_entry *de;
119 struct buffer_head *bh;
120 struct inode *next;
121
122 PRINTK (("msdos_lookup\n"));
123
124 *result = NULL;
125 if (!dir) return -ENOENT;
126 if (!S_ISDIR(dir->i_mode)) {
127 iput(dir);
128 return -ENOENT;
129 }
130 PRINTK (("msdos_lookup 2\n"));
131 if (len == 1 && name[0] == '.') {
132 *result = dir;
133 return 0;
134 }
135 if (len == 2 && name[0] == '.' && name[1] == '.') {
136 ino = msdos_parent_ino(dir,0);
137 iput(dir);
138 if (ino < 0) return ino;
139 if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
140 return 0;
141 }
142 PRINTK (("msdos_lookup 3\n"));
143 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
144 iput(dir);
145 return res;
146 }
147 PRINTK (("msdos_lookup 4\n"));
148 if (bh) brelse(bh);
149 PRINTK (("msdos_lookup 4.5\n"));
150
151 if (!(*result = iget(dir->i_sb,ino))) {
152 iput(dir);
153 return -EACCES;
154 }
155 PRINTK (("msdos_lookup 5\n"));
156 if (MSDOS_I(*result)->i_busy) {
157 iput(*result);
158 iput(dir);
159 return -ENOENT;
160 }
161 PRINTK (("msdos_lookup 6\n"));
162 while (MSDOS_I(*result)->i_old) {
163 next = MSDOS_I(*result)->i_old;
164 iput(*result);
165 if (!(*result = iget(next->i_sb,next->i_ino))) {
166 fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
167 iput(dir);
168 return -ENOENT;
169 }
170 }
171 PRINTK (("msdos_lookup 7\n"));
172 iput(dir);
173 PRINTK (("msdos_lookup 8\n"));
174 return 0;
175 }
176
177
178
179
180 static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
181 struct inode **result)
182 {
183 struct super_block *sb = dir->i_sb;
184 struct buffer_head *bh;
185 struct msdos_dir_entry *de;
186 int res,ino;
187
188 if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
189 if (res != -ENOENT) return res;
190 if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
191 if ((res = msdos_add_cluster(dir)) < 0) return res;
192 if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
193 }
194
195
196
197 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
198 dir->i_dirt = 1;
199 memcpy(de->name,name,MSDOS_NAME);
200 memset(de->unused, 0, sizeof(de->unused));
201 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
202 de->start = 0;
203 date_unix2dos(dir->i_mtime,&de->time,&de->date);
204 de->size = 0;
205 mark_buffer_dirty(bh, 1);
206 if ((*result = iget(dir->i_sb,ino)) != NULL)
207 msdos_read_inode(*result);
208 brelse(bh);
209 if (!*result) return -EIO;
210 (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
211 CURRENT_TIME;
212 (*result)->i_dirt = 1;
213 return 0;
214 }
215
216
217 int msdos_create(struct inode *dir,const char *name,int len,int mode,
218 struct inode **result)
219 {
220 struct super_block *sb = dir->i_sb;
221 struct buffer_head *bh;
222 struct msdos_dir_entry *de;
223 char msdos_name[MSDOS_NAME];
224 int ino,res;
225
226 if (!dir) return -ENOENT;
227 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
228 msdos_name,0)) < 0) {
229 iput(dir);
230 return res;
231 }
232 lock_creation();
233 if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
234 unlock_creation();
235 brelse(bh);
236 iput(dir);
237 return -EEXIST;
238 }
239 res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
240 unlock_creation();
241 iput(dir);
242 return res;
243 }
244
245
246 #ifdef DEBUG
247
248 static void dump_fat(struct super_block *sb,int start)
249 {
250 printk("[");
251 while (start) {
252 printk("%d ",start);
253 start = fat_access(sb,start,-1);
254 if (!start) {
255 printk("ERROR");
256 break;
257 }
258 if (start == -1) break;
259 }
260 printk("]\n");
261 }
262
263 #endif
264
265
266 int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
267 {
268 struct super_block *sb = dir->i_sb;
269 struct buffer_head *bh;
270 struct msdos_dir_entry *de;
271 struct inode *inode,*dot;
272 char msdos_name[MSDOS_NAME];
273 int ino,res;
274
275 if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
276 msdos_name,0)) < 0) {
277 iput(dir);
278 return res;
279 }
280 lock_creation();
281 if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
282 unlock_creation();
283 brelse(bh);
284 iput(dir);
285 return -EEXIST;
286 }
287 if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
288 unlock_creation();
289 iput(dir);
290 return res;
291 }
292 dir->i_nlink++;
293 inode->i_nlink = 2;
294 MSDOS_I(inode)->i_busy = 1;
295 if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
296 if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
297 goto mkdir_error;
298 dot->i_size = inode->i_size;
299 MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
300 dot->i_nlink = inode->i_nlink;
301 dot->i_dirt = 1;
302 iput(dot);
303 if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
304 goto mkdir_error;
305 unlock_creation();
306 dot->i_size = dir->i_size;
307 MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
308 dot->i_nlink = dir->i_nlink;
309 dot->i_dirt = 1;
310 MSDOS_I(inode)->i_busy = 0;
311 iput(dot);
312 iput(inode);
313 iput(dir);
314 return 0;
315 mkdir_error:
316 iput(inode);
317 if (msdos_rmdir(dir,name,len) < 0)
318 fs_panic(dir->i_sb,"rmdir in mkdir failed");
319 unlock_creation();
320 return res;
321 }
322
323
324 static int msdos_empty(struct inode *dir)
325 {
326 struct super_block *sb = dir->i_sb;
327 loff_t pos;
328 struct buffer_head *bh;
329 struct msdos_dir_entry *de;
330
331 if (dir->i_count > 1)
332 return -EBUSY;
333 if (MSDOS_I(dir)->i_start) {
334 pos = 0;
335 bh = NULL;
336 while (msdos_get_entry(dir,&pos,&bh,&de) > -1)
337 if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
338 MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
339 MSDOS_NAME)) {
340 brelse(bh);
341 return -ENOTEMPTY;
342 }
343 if (bh)
344 brelse(bh);
345 }
346 return 0;
347 }
348
349
350 int msdos_rmdir(struct inode *dir,const char *name,int len)
351 {
352 struct super_block *sb = dir->i_sb;
353 int res,ino;
354 struct buffer_head *bh;
355 struct msdos_dir_entry *de;
356 struct inode *inode;
357
358 bh = NULL;
359 inode = NULL;
360 res = -EPERM;
361 if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
362 goto rmdir_done;
363 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
364 res = -ENOENT;
365 if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
366 res = -ENOTDIR;
367 if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
368 res = -EBUSY;
369 if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
370 res = msdos_empty(inode);
371 if (res)
372 goto rmdir_done;
373 inode->i_nlink = 0;
374 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
375 dir->i_nlink--;
376 inode->i_dirt = dir->i_dirt = 1;
377 de->name[0] = DELETED_FLAG;
378 mark_buffer_dirty(bh, 1);
379 res = 0;
380 rmdir_done:
381 brelse(bh);
382 iput(dir);
383 iput(inode);
384 return res;
385 }
386
387
388 static int msdos_unlinkx(
389 struct inode *dir,
390 const char *name,
391 int len,
392 int nospc)
393 {
394 struct super_block *sb = dir->i_sb;
395 int res,ino;
396 struct buffer_head *bh;
397 struct msdos_dir_entry *de;
398 struct inode *inode;
399
400 bh = NULL;
401 inode = NULL;
402 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
403 goto unlink_done;
404 if (!(inode = iget(dir->i_sb,ino))) {
405 res = -ENOENT;
406 goto unlink_done;
407 }
408 if (!S_ISREG(inode->i_mode) && nospc){
409 res = -EPERM;
410 goto unlink_done;
411 }
412 inode->i_nlink = 0;
413 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
414 MSDOS_I(inode)->i_busy = 1;
415 inode->i_dirt = dir->i_dirt = 1;
416 de->name[0] = DELETED_FLAG;
417 mark_buffer_dirty(bh, 1);
418 unlink_done:
419 brelse(bh);
420 iput(inode);
421 iput(dir);
422 return res;
423 }
424
425 int msdos_unlink(struct inode *dir,const char *name,int len)
426 {
427 return msdos_unlinkx (dir,name,len,1);
428 }
429
430
431
432 int msdos_unlink_umsdos(struct inode *dir,const char *name,int len)
433 {
434 return msdos_unlinkx (dir,name,len,0);
435 }
436
437 static int rename_same_dir(struct inode *old_dir,char *old_name,
438 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
439 struct msdos_dir_entry *old_de,int old_ino)
440 {
441 struct super_block *sb = old_dir->i_sb;
442 struct buffer_head *new_bh;
443 struct msdos_dir_entry *new_de;
444 struct inode *new_inode,*old_inode;
445 int new_ino,exists,error;
446
447 if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
448 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
449 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
450 if (exists) brelse(new_bh);
451 return -ENOENT;
452 }
453 if (exists) {
454 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
455 brelse(new_bh);
456 return -EIO;
457 }
458 error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
459 msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
460 ? -EPERM : 0;
461 if (error) {
462 iput(new_inode);
463 brelse(new_bh);
464 return error;
465 }
466 if (S_ISDIR(new_inode->i_mode)) {
467 new_dir->i_nlink--;
468 new_dir->i_dirt = 1;
469 }
470 new_inode->i_nlink = 0;
471 MSDOS_I(new_inode)->i_busy = 1;
472 new_inode->i_dirt = 1;
473 new_de->name[0] = DELETED_FLAG;
474 mark_buffer_dirty(new_bh, 1);
475 iput(new_inode);
476 brelse(new_bh);
477 }
478 memcpy(old_de->name,new_name,MSDOS_NAME);
479 mark_buffer_dirty(old_bh, 1);
480 if (MSDOS_SB(old_dir->i_sb)->conversion == 'a')
481 if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
482 msdos_read_inode(old_inode);
483 iput(old_inode);
484 }
485 return 0;
486 }
487
488
489 static int rename_diff_dir(struct inode *old_dir,char *old_name,
490 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
491 struct msdos_dir_entry *old_de,int old_ino)
492 {
493 struct super_block *sb = old_dir->i_sb;
494 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
495 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
496 struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
497 int new_ino,free_ino,dotdot_ino;
498 int error,exists,ino;
499
500 if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
501 if (old_ino == new_dir->i_ino) return -EINVAL;
502 if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
503 while (walk->i_ino != MSDOS_ROOT_INO) {
504 ino = msdos_parent_ino(walk,1);
505 iput(walk);
506 if (ino < 0) return ino;
507 if (ino == old_ino) return -EINVAL;
508 if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
509 }
510 iput(walk);
511 while ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) <
512 0) {
513 if (error != -ENOENT) return error;
514 error = msdos_add_cluster(new_dir);
515 if (error) return error;
516 }
517 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
518 if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
519 brelse(free_bh);
520 if (exists) brelse(new_bh);
521 return -EIO;
522 }
523 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
524 iput(old_inode);
525 brelse(free_bh);
526 if (exists) brelse(new_bh);
527 return -ENOENT;
528 }
529 new_inode = NULL;
530 if (exists) {
531 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
532 iput(old_inode);
533 brelse(new_bh);
534 return -EIO;
535 }
536 error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
537 msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
538 ? -EPERM : 0;
539 if (error) {
540 iput(new_inode);
541 iput(old_inode);
542 brelse(new_bh);
543 return error;
544 }
545 new_inode->i_nlink = 0;
546 MSDOS_I(new_inode)->i_busy = 1;
547 new_inode->i_dirt = 1;
548 new_de->name[0] = DELETED_FLAG;
549 mark_buffer_dirty(new_bh, 1);
550 }
551 memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
552 memcpy(free_de->name,new_name,MSDOS_NAME);
553 if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
554 free_de->name[0] = DELETED_FLAG;
555
556 brelse(free_bh);
557 if (exists) {
558 iput(new_inode);
559 brelse(new_bh);
560 }
561 return -EIO;
562 }
563 if (exists && S_ISDIR(new_inode->i_mode)) {
564 new_dir->i_nlink--;
565 new_dir->i_dirt = 1;
566 }
567 msdos_read_inode(free_inode);
568 MSDOS_I(old_inode)->i_busy = 1;
569 cache_inval_inode(old_inode);
570 old_inode->i_dirt = 1;
571 old_de->name[0] = DELETED_FLAG;
572 mark_buffer_dirty(old_bh, 1);
573 mark_buffer_dirty(free_bh, 1);
574 if (!exists) iput(free_inode);
575 else {
576 MSDOS_I(new_inode)->i_depend = free_inode;
577 MSDOS_I(free_inode)->i_old = new_inode;
578
579 iput(new_inode);
580 brelse(new_bh);
581 }
582 if (S_ISDIR(old_inode->i_mode)) {
583 if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
584 &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
585 if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
586 brelse(dotdot_bh);
587 error = -EIO;
588 goto rename_done;
589 }
590 dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
591 MSDOS_I(new_dir)->i_start;
592 dotdot_inode->i_dirt = 1;
593 mark_buffer_dirty(dotdot_bh, 1);
594 old_dir->i_nlink--;
595 new_dir->i_nlink++;
596
597 dotdot_inode->i_nlink = new_dir->i_nlink;
598 iput(dotdot_inode);
599 brelse(dotdot_bh);
600 }
601 error = 0;
602 rename_done:
603 brelse(free_bh);
604 iput(old_inode);
605 return error;
606 }
607
608
609 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
610 struct inode *new_dir,const char *new_name,int new_len)
611 {
612 struct super_block *sb = old_dir->i_sb;
613 char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
614 struct buffer_head *old_bh;
615 struct msdos_dir_entry *old_de;
616 int old_ino,error;
617
618 if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
619 old_name,old_len,old_msdos_name,1)) < 0) goto rename_done;
620 if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
621 new_name,new_len,new_msdos_name,0)) < 0) goto rename_done;
622 if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
623 &old_ino)) < 0) goto rename_done;
624 lock_creation();
625 if (old_dir == new_dir)
626 error = rename_same_dir(old_dir,old_msdos_name,new_dir,
627 new_msdos_name,old_bh,old_de,old_ino);
628 else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
629 new_msdos_name,old_bh,old_de,old_ino);
630 unlock_creation();
631 brelse(old_bh);
632 rename_done:
633 iput(old_dir);
634 iput(new_dir);
635 return error;
636 }