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