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) goto rmdir_done;
372 res = msdos_empty(inode);
373 if (res)
374 goto rmdir_done;
375 inode->i_nlink = 0;
376 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
377 dir->i_nlink--;
378 inode->i_dirt = dir->i_dirt = 1;
379 de->name[0] = DELETED_FLAG;
380 mark_buffer_dirty(bh, 1);
381 res = 0;
382 rmdir_done:
383 brelse(bh);
384 iput(dir);
385 iput(inode);
386 return res;
387 }
388
389
390 static int msdos_unlinkx(
391 struct inode *dir,
392 const char *name,
393 int len,
394 int nospc)
395 {
396 struct super_block *sb = dir->i_sb;
397 int res,ino;
398 struct buffer_head *bh;
399 struct msdos_dir_entry *de;
400 struct inode *inode;
401
402 bh = NULL;
403 inode = NULL;
404 if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
405 goto unlink_done;
406 if (!(inode = iget(dir->i_sb,ino))) {
407 res = -ENOENT;
408 goto unlink_done;
409 }
410 if (!S_ISREG(inode->i_mode) && nospc){
411 res = -EPERM;
412 goto unlink_done;
413 }
414 inode->i_nlink = 0;
415 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
416 MSDOS_I(inode)->i_busy = 1;
417 inode->i_dirt = dir->i_dirt = 1;
418 de->name[0] = DELETED_FLAG;
419 mark_buffer_dirty(bh, 1);
420 unlink_done:
421 brelse(bh);
422 iput(inode);
423 iput(dir);
424 return res;
425 }
426
427 int msdos_unlink(struct inode *dir,const char *name,int len)
428 {
429 return msdos_unlinkx (dir,name,len,1);
430 }
431
432
433
434 int msdos_unlink_umsdos(struct inode *dir,const char *name,int len)
435 {
436 return msdos_unlinkx (dir,name,len,0);
437 }
438
439 static int rename_same_dir(struct inode *old_dir,char *old_name,
440 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
441 struct msdos_dir_entry *old_de,int old_ino)
442 {
443 struct super_block *sb = old_dir->i_sb;
444 struct buffer_head *new_bh;
445 struct msdos_dir_entry *new_de;
446 struct inode *new_inode,*old_inode;
447 int new_ino,exists,error;
448
449 if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
450 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
451 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
452 if (exists) brelse(new_bh);
453 return -ENOENT;
454 }
455 if (exists) {
456 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
457 brelse(new_bh);
458 return -EIO;
459 }
460 error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
461 msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
462 ? -EPERM : 0;
463 if (error) {
464 iput(new_inode);
465 brelse(new_bh);
466 return error;
467 }
468 if (S_ISDIR(new_inode->i_mode)) {
469 new_dir->i_nlink--;
470 new_dir->i_dirt = 1;
471 }
472 new_inode->i_nlink = 0;
473 MSDOS_I(new_inode)->i_busy = 1;
474 new_inode->i_dirt = 1;
475 new_de->name[0] = DELETED_FLAG;
476 mark_buffer_dirty(new_bh, 1);
477 iput(new_inode);
478 brelse(new_bh);
479 }
480 memcpy(old_de->name,new_name,MSDOS_NAME);
481 mark_buffer_dirty(old_bh, 1);
482 if (MSDOS_SB(old_dir->i_sb)->conversion == 'a')
483 if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
484 msdos_read_inode(old_inode);
485 iput(old_inode);
486 }
487 return 0;
488 }
489
490
491 static int rename_diff_dir(struct inode *old_dir,char *old_name,
492 struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
493 struct msdos_dir_entry *old_de,int old_ino)
494 {
495 struct super_block *sb = old_dir->i_sb;
496 struct buffer_head *new_bh,*free_bh,*dotdot_bh;
497 struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
498 struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
499 int new_ino,free_ino,dotdot_ino;
500 int error,exists,ino;
501
502 if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
503 if (old_ino == new_dir->i_ino) return -EINVAL;
504 if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
505 while (walk->i_ino != MSDOS_ROOT_INO) {
506 ino = msdos_parent_ino(walk,1);
507 iput(walk);
508 if (ino < 0) return ino;
509 if (ino == old_ino) return -EINVAL;
510 if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
511 }
512 iput(walk);
513 while ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) <
514 0) {
515 if (error != -ENOENT) return error;
516 error = msdos_add_cluster(new_dir);
517 if (error) return error;
518 }
519 exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
520 if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
521 brelse(free_bh);
522 if (exists) brelse(new_bh);
523 return -EIO;
524 }
525 if (*(unsigned char *) old_de->name == DELETED_FLAG) {
526 iput(old_inode);
527 brelse(free_bh);
528 if (exists) brelse(new_bh);
529 return -ENOENT;
530 }
531 new_inode = NULL;
532 if (exists) {
533 if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
534 iput(old_inode);
535 brelse(new_bh);
536 return -EIO;
537 }
538 error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
539 msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
540 ? -EPERM : 0;
541 if (error) {
542 iput(new_inode);
543 iput(old_inode);
544 brelse(new_bh);
545 return error;
546 }
547 new_inode->i_nlink = 0;
548 MSDOS_I(new_inode)->i_busy = 1;
549 new_inode->i_dirt = 1;
550 new_de->name[0] = DELETED_FLAG;
551 mark_buffer_dirty(new_bh, 1);
552 }
553 memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
554 memcpy(free_de->name,new_name,MSDOS_NAME);
555 if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
556 free_de->name[0] = DELETED_FLAG;
557
558 brelse(free_bh);
559 if (exists) {
560 iput(new_inode);
561 brelse(new_bh);
562 }
563 return -EIO;
564 }
565 if (exists && S_ISDIR(new_inode->i_mode)) {
566 new_dir->i_nlink--;
567 new_dir->i_dirt = 1;
568 }
569 msdos_read_inode(free_inode);
570 MSDOS_I(old_inode)->i_busy = 1;
571 cache_inval_inode(old_inode);
572 old_inode->i_dirt = 1;
573 old_de->name[0] = DELETED_FLAG;
574 mark_buffer_dirty(old_bh, 1);
575 mark_buffer_dirty(free_bh, 1);
576 if (!exists) iput(free_inode);
577 else {
578 MSDOS_I(new_inode)->i_depend = free_inode;
579 MSDOS_I(free_inode)->i_old = new_inode;
580
581 iput(new_inode);
582 brelse(new_bh);
583 }
584 if (S_ISDIR(old_inode->i_mode)) {
585 if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
586 &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
587 if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
588 brelse(dotdot_bh);
589 error = -EIO;
590 goto rename_done;
591 }
592 dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
593 MSDOS_I(new_dir)->i_start;
594 dotdot_inode->i_dirt = 1;
595 mark_buffer_dirty(dotdot_bh, 1);
596 old_dir->i_nlink--;
597 new_dir->i_nlink++;
598
599 dotdot_inode->i_nlink = new_dir->i_nlink;
600 iput(dotdot_inode);
601 brelse(dotdot_bh);
602 }
603 error = 0;
604 rename_done:
605 brelse(free_bh);
606 iput(old_inode);
607 return error;
608 }
609
610
611 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
612 struct inode *new_dir,const char *new_name,int new_len)
613 {
614 struct super_block *sb = old_dir->i_sb;
615 char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
616 struct buffer_head *old_bh;
617 struct msdos_dir_entry *old_de;
618 int old_ino,error;
619
620 if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
621 old_name,old_len,old_msdos_name,1)) < 0) goto rename_done;
622 if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
623 new_name,new_len,new_msdos_name,0)) < 0) goto rename_done;
624 if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
625 &old_ino)) < 0) goto rename_done;
626 lock_creation();
627 if (old_dir == new_dir)
628 error = rename_same_dir(old_dir,old_msdos_name,new_dir,
629 new_msdos_name,old_bh,old_de,old_ino);
630 else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
631 new_msdos_name,old_bh,old_de,old_ino);
632 unlock_creation();
633 brelse(old_bh);
634 rename_done:
635 iput(old_dir);
636 iput(new_dir);
637 return error;
638 }