|
|
1.1 root 1: /*
2: * linux/fs/msdos/namei.c
3: *
4: * Written 1992 by Werner Almesberger
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: /* MS-DOS "device special files" */
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:
1.1.1.2 ! root 25: /* Characters that are undesirable in an MS-DOS file name */
! 26:
! 27: static char bad_chars[] = "*?<>|\" ";
! 28: static char bad_if_strict[] = "+=,;";
! 29:
! 30:
1.1 root 31: /* Formats an MS-DOS file name. Rejects invalid names. */
32:
33: static int msdos_format_name(char conv,const char *name,int len,char *res)
34: {
35: char *walk,**reserved;
36: char c;
37: int space;
38:
39: if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL;
40: if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
41: get_fs_byte(name+1) == '.'))) {
42: memset(res+1,' ',10);
43: while (len--) *res++ = '.';
44: return 0;
45: }
46: space = 0; /* to make GCC happy */
47: c = 0;
48: for (walk = res; len && walk-res < 8; walk++) {
49: c = get_fs_byte(name++);
50: len--;
1.1.1.2 ! root 51: if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
! 52: if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
! 53: if (c >= 'A' && c <= 'Z') {
! 54: if (conv == 's') return -EINVAL;
1.1 root 55: c += 32;
56: }
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 = get_fs_byte(name++);
65: len--;
66: if (c != '.') return -EINVAL;
67: }
68: while (c != '.' && len--) c = get_fs_byte(name++);
69: if (walk == res) return -EINVAL;
70: if (c == '.') {
71: while (walk-res < 8) *walk++ = ' ';
72: while (len > 0 && walk-res < MSDOS_NAME) {
73: c = get_fs_byte(name++);
74: len--;
1.1.1.2 ! root 75: if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
! 76: if (conv == 's' && strchr(bad_if_strict,c))
! 77: return -EINVAL;
1.1 root 78: if (c < ' ' || c == ':' || c == '\\' || c == '.')
79: return -EINVAL;
80: if (c >= 'A' && c <= 'Z') {
1.1.1.2 ! root 81: if (conv == 's') return -EINVAL;
1.1 root 82: c += 32;
83: }
84: space = c == ' ';
85: *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
86: }
87: if (space) return -EINVAL;
88: if (conv == 's' && len) return -EINVAL;
89: }
90: while (walk-res < MSDOS_NAME) *walk++ = ' ';
91: for (reserved = reserved_names; *reserved; reserved++)
92: if (!strncmp(res,*reserved,8)) return -EINVAL;
93: return 0;
94: }
95:
96:
97: /* Locates a directory entry. */
98:
99: static int msdos_find(struct inode *dir,const char *name,int len,
100: struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
101: {
102: char msdos_name[MSDOS_NAME];
103: int res;
104:
105: if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
106: msdos_name)) < 0) return res;
107: return msdos_scan(dir,msdos_name,bh,de,ino);
108: }
109:
110:
111: int msdos_lookup(struct inode *dir,const char *name,int len,
112: struct inode **result)
113: {
114: int ino,res;
115: struct msdos_dir_entry *de;
116: struct buffer_head *bh;
117: struct inode *next;
118:
119: *result = NULL;
120: if (!dir) return -ENOENT;
121: if (!S_ISDIR(dir->i_mode)) {
122: iput(dir);
123: return -ENOENT;
124: }
125: if (len == 1 && get_fs_byte(name) == '.') {
126: *result = dir;
127: return 0;
128: }
129: if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.')
130: {
131: ino = msdos_parent_ino(dir,0);
132: iput(dir);
133: if (ino < 0) return ino;
134: if (!(*result = iget(dir->i_dev,ino))) return -EACCES;
135: return 0;
136: }
137: if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
138: iput(dir);
139: return res;
140: }
141: if (bh) brelse(bh);
142: /* printk("lookup: ino=%d\r\n",ino); */
143: if (!(*result = iget(dir->i_dev,ino))) {
144: iput(dir);
145: return -EACCES;
146: }
1.1.1.2 ! root 147: if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
1.1 root 148: iput(*result);
149: iput(dir);
150: return -ENOENT;
151: }
1.1.1.2 ! root 152: while (MSDOS_I(*result)->i_old) {
! 153: next = MSDOS_I(*result)->i_old;
1.1 root 154: iput(*result);
155: if (!(*result = iget(next->i_dev,next->i_ino)))
156: panic("msdos_lookup: Can't happen");
157: }
158: iput(dir);
159: return 0;
160: }
161:
162:
163: /* Creates a directory entry (name is already formatted). */
164:
165: static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
166: struct inode **result)
167: {
168: struct buffer_head *bh;
169: struct msdos_dir_entry *de;
170: int res,ino;
171:
172: if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
173: if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
174: if ((res = msdos_add_cluster(dir)) < 0) return res;
175: if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
176: }
177: memcpy(de->name,name,MSDOS_NAME);
178: de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
179: de->start = 0;
180: date_unix2dos(CURRENT_TIME,&de->time,&de->date);
181: de->size = 0;
182: bh->b_dirt = 1;
183: if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result);
184: brelse(bh);
185: if (!*result) return -EIO;
186: (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
187: CURRENT_TIME;
188: (*result)->i_dirt = 1;
189: return 0;
190: }
191:
192:
193: int msdos_create(struct inode *dir,const char *name,int len,int mode,
194: struct inode **result)
195: {
196: struct buffer_head *bh;
197: struct msdos_dir_entry *de;
198: char msdos_name[MSDOS_NAME];
199: int ino,res;
200:
201: if (!dir) return -ENOENT;
202: if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
203: msdos_name)) < 0) {
204: iput(dir);
205: return res;
206: }
207: lock_creation();
208: if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
209: unlock_creation();
210: brelse(bh);
211: iput(dir);
212: return -EEXIST;
213: }
214: res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
215: unlock_creation();
216: iput(dir);
217: return res;
218: }
219:
220:
1.1.1.2 ! root 221: #ifdef DEBUG
! 222:
! 223: static void dump_fat(struct super_block *sb,int start)
! 224: {
! 225: printk("[");
! 226: while (start) {
! 227: printk("%d ",start);
! 228: start = fat_access(sb,start,-1);
! 229: if (!start) {
! 230: printk("ERROR");
! 231: break;
! 232: }
! 233: if (start == -1) break;
! 234: }
! 235: printk("]\n");
! 236: }
! 237:
! 238: #endif
! 239:
! 240:
1.1 root 241: int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
242: {
243: struct buffer_head *bh;
244: struct msdos_dir_entry *de;
245: struct inode *inode,*dot;
246: char msdos_name[MSDOS_NAME];
247: int ino,res;
248:
249: if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
250: msdos_name)) < 0) {
251: iput(dir);
252: return res;
253: }
254: lock_creation();
255: if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
256: unlock_creation();
257: brelse(bh);
258: iput(dir);
259: return -EEXIST;
260: }
261: if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
262: unlock_creation();
263: iput(dir);
264: return res;
265: }
1.1.1.2 ! root 266: dir->i_nlink++;
! 267: inode->i_nlink = 2; /* no need to mark them dirty */
! 268: MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
1.1 root 269: if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
270: if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
271: goto mkdir_error;
1.1.1.2 ! root 272: dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
! 273: MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
! 274: dot->i_nlink = inode->i_nlink;
1.1 root 275: dot->i_dirt = 1;
276: iput(dot);
277: if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
278: goto mkdir_error;
279: unlock_creation();
280: dot->i_size = dir->i_size;
1.1.1.2 ! root 281: MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
! 282: dot->i_nlink = dir->i_nlink;
1.1 root 283: dot->i_dirt = 1;
1.1.1.2 ! root 284: MSDOS_I(inode)->i_busy = 0;
1.1 root 285: iput(dot);
286: iput(inode);
287: iput(dir);
288: return 0;
289: mkdir_error:
290: iput(inode);
291: if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
292: unlock_creation();
293: return res;
294: }
295:
296:
297: int msdos_rmdir(struct inode *dir,const char *name,int len)
298: {
299: int res,ino,pos;
300: struct buffer_head *bh,*dbh;
301: struct msdos_dir_entry *de,*dde;
302: struct inode *inode;
303:
304: bh = NULL;
305: inode = NULL;
306: res = -EINVAL;
1.1.1.2 ! root 307: if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
! 308: get_fs_byte(name+1) == '.'))) goto rmdir_done;
1.1 root 309: if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
310: res = -ENOENT;
311: if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
312: res = -ENOTDIR;
313: if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
314: res = -EBUSY;
315: if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
316: if (inode->i_count > 1) goto rmdir_done;
1.1.1.2 ! root 317: if (MSDOS_I(inode)->i_start) { /* may be zero in mkdir */
1.1 root 318: res = -ENOTEMPTY;
319: pos = 0;
320: dbh = NULL;
321: while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
322: if (dde->name[0] && ((unsigned char *) dde->name)[0] !=
323: DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,
324: MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
325: MSDOS_NAME)) goto rmdir_done;
326: if (dbh) brelse(dbh);
327: }
328: inode->i_nlink = 0;
329: dir->i_mtime = CURRENT_TIME;
1.1.1.2 ! root 330: dir->i_nlink--;
1.1 root 331: inode->i_dirt = dir->i_dirt = 1;
332: de->name[0] = DELETED_FLAG;
333: bh->b_dirt = 1;
334: res = 0;
335: rmdir_done:
336: brelse(bh);
337: iput(dir);
338: iput(inode);
339: return res;
340: }
341:
342:
343: int msdos_unlink(struct inode *dir,const char *name,int len)
344: {
345: int res,ino;
346: struct buffer_head *bh;
347: struct msdos_dir_entry *de;
348: struct inode *inode;
349:
350: bh = NULL;
351: inode = NULL;
352: if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
353: goto unlink_done;
354: if (!(inode = iget(dir->i_dev,ino))) {
355: res = -ENOENT;
356: goto unlink_done;
357: }
358: if (!S_ISREG(inode->i_mode)) {
359: res = -EPERM;
360: goto unlink_done;
361: }
362: inode->i_nlink = 0;
1.1.1.2 ! root 363: MSDOS_I(inode)->i_busy = 1;
1.1 root 364: inode->i_dirt = 1;
365: de->name[0] = DELETED_FLAG;
366: bh->b_dirt = 1;
367: unlink_done:
368: brelse(bh);
369: iput(inode);
370: iput(dir);
371: return res;
372: }
373:
374:
375: static int rename_same_dir(struct inode *old_dir,char *old_name,
376: struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
377: struct msdos_dir_entry *old_de,int old_ino)
378: {
379: struct buffer_head *new_bh;
380: struct msdos_dir_entry *new_de;
381: struct inode *new_inode,*old_inode;
382: int new_ino;
383: int exists;
384:
385: if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
386: exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
387: if (*(unsigned char *) old_de->name == DELETED_FLAG) {
388: if (exists) brelse(new_bh);
389: return -ENOENT;
390: }
391: if (exists) {
392: if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
393: brelse(new_bh);
394: return -EIO;
395: }
396: if (S_ISDIR(new_inode->i_mode)) {
397: iput(new_inode);
398: brelse(new_bh);
399: return -EPERM;
400: }
401: new_inode->i_nlink = 0;
1.1.1.2 ! root 402: MSDOS_I(new_inode)->i_busy = 1;
1.1 root 403: new_inode->i_dirt = 1;
404: new_de->name[0] = DELETED_FLAG;
405: new_bh->b_dirt = 1;
406: iput(new_inode);
407: brelse(new_bh);
408: }
409: memcpy(old_de->name,new_name,MSDOS_NAME);
410: old_bh->b_dirt = 1;
411: if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
412: if (old_inode = iget(old_dir->i_dev,old_ino)) {
413: msdos_read_inode(old_inode);
414: iput(old_inode);
415: }
416: return 0;
417: }
418:
419:
420: static int rename_diff_dir(struct inode *old_dir,char *old_name,
421: struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
422: struct msdos_dir_entry *old_de,int old_ino)
423: {
424: struct buffer_head *new_bh,*free_bh,*dotdot_bh;
425: struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
426: struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
427: int new_ino,free_ino,dotdot_ino;
428: int error,exists,ino;
429:
430: if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
431: if (old_ino == new_dir->i_ino) return -EINVAL;
432: if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO;
433: while (walk->i_ino != MSDOS_ROOT_INO) {
434: ino = msdos_parent_ino(walk,1);
435: iput(walk);
436: if (ino < 0) return ino;
437: if (ino == old_ino) return -EINVAL;
438: if (!(walk = iget(new_dir->i_dev,ino))) return -EIO;
439: }
440: iput(walk);
441: if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
442: return error;
443: exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
444: >= 0;
445: if (!(old_inode = iget(old_dir->i_dev,old_ino))) {
446: brelse(free_bh);
447: if (exists) brelse(new_bh);
448: return -EIO;
449: }
450: if (*(unsigned char *) old_de->name == DELETED_FLAG) {
451: iput(old_inode);
452: brelse(free_bh);
453: if (exists) brelse(new_bh);
454: return -ENOENT;
455: }
456: new_inode = NULL; /* to make GCC happy */
457: if (exists) {
458: if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
459: iput(old_inode);
460: brelse(new_bh);
461: return -EIO;
462: }
463: if (S_ISDIR(new_inode->i_mode)) {
464: iput(new_inode);
465: iput(old_inode);
466: brelse(new_bh);
467: return -EPERM;
468: }
469: new_inode->i_nlink = 0;
1.1.1.2 ! root 470: MSDOS_I(new_inode)->i_busy = 1;
1.1 root 471: new_inode->i_dirt = 1;
472: new_de->name[0] = DELETED_FLAG;
473: new_bh->b_dirt = 1;
474: }
475: memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
476: memcpy(free_de->name,new_name,MSDOS_NAME);
477: if (!(free_inode = iget(new_dir->i_dev,free_ino))) {
478: free_de->name[0] = DELETED_FLAG;
479: /* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
480: brelse(free_bh);
481: if (exists) {
482: iput(new_inode);
483: brelse(new_bh);
484: }
485: return -EIO;
486: }
487: msdos_read_inode(free_inode);
1.1.1.2 ! root 488: MSDOS_I(old_inode)->i_busy = 1;
! 489: cache_inval_inode(old_inode);
1.1 root 490: old_inode->i_dirt = 1;
491: old_de->name[0] = DELETED_FLAG;
492: old_bh->b_dirt = 1;
493: free_bh->b_dirt = 1;
494: if (!exists) iput(free_inode);
495: else {
1.1.1.2 ! root 496: MSDOS_I(new_inode)->i_depend = free_inode;
! 497: MSDOS_I(free_inode)->i_old = new_inode;
1.1 root 498: /* free_inode is put when putting new_inode */
499: iput(new_inode);
500: brelse(new_bh);
501: }
502: if (S_ISDIR(old_inode->i_mode)) {
503: if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
504: &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
505: if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) {
506: brelse(dotdot_bh);
507: error = -EIO;
508: goto rename_done;
509: }
1.1.1.2 ! root 510: dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
! 511: MSDOS_I(new_dir)->i_start;
1.1 root 512: dotdot_inode->i_dirt = 1;
513: dotdot_bh->b_dirt = 1;
514: iput(dotdot_inode);
515: brelse(dotdot_bh);
1.1.1.2 ! root 516: old_dir->i_nlink--;
! 517: new_dir->i_nlink++;
! 518: /* no need to mark them dirty */
1.1 root 519: }
520: error = 0;
521: rename_done:
522: brelse(free_bh);
523: iput(old_inode);
524: return error;
525: }
526:
527:
528: int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
529: struct inode *new_dir,const char *new_name,int new_len)
530: {
531: char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
532: struct buffer_head *old_bh;
533: struct msdos_dir_entry *old_de;
534: int old_ino,error;
535:
536: if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
537: old_name,old_len,old_msdos_name)) < 0) goto rename_done;
538: if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
539: new_name,new_len,new_msdos_name)) < 0) goto rename_done;
540: if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
541: &old_ino)) < 0) goto rename_done;
542: lock_creation();
543: if (old_dir == new_dir)
544: error = rename_same_dir(old_dir,old_msdos_name,new_dir,
545: new_msdos_name,old_bh,old_de,old_ino);
546: else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
547: new_msdos_name,old_bh,old_de,old_ino);
548: unlock_creation();
549: brelse(old_bh);
550: rename_done:
551: iput(old_dir);
552: iput(new_dir);
553: return error;
554: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.