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