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