static int msdos_create_entry(struct inode *dir,char *name,int is_dir, struct inode **result) { struct buffer_head *bh; struct msdos_dir_entry *de; int res,ino; if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) { if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC; if ((res = msdos_add_cluster(dir)) < 0) return res; if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res; } memcpy(de->name,name,MSDOS_NAME); de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; de->start = 0; date_unix2dos(CURRENT_TIME,&de->time,&de->date); de->size = 0; bh->b_dirt = 1; if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result); brelse(bh); if (!*result) return -EIO; (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime = CURRENT_TIME; (*result)->i_dirt = 1; return 0; }
int msdos_mkdir(struct inode *dir,const char *name,int len,int mode) { struct buffer_head *bh; struct msdos_dir_entry *de; struct inode *inode,*dot; char msdos_name[MSDOS_NAME]; int ino,res; if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, msdos_name)) < 0) { iput(dir); return res; } lock_creation(); if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) { unlock_creation(); brelse(bh); iput(dir); return -EEXIST; } if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) { unlock_creation(); iput(dir); return res; } dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ MSDOS_I(inode)->i_busy = 1; /* prevent lookups */ if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error; if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0) goto mkdir_error; dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */ MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start; dot->i_nlink = inode->i_nlink; dot->i_dirt = 1; iput(dot); if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0) goto mkdir_error; unlock_creation(); dot->i_size = dir->i_size; MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start; dot->i_nlink = dir->i_nlink; dot->i_dirt = 1; MSDOS_I(inode)->i_busy = 0; iput(dot); iput(inode); iput(dir); return 0; mkdir_error: iput(inode); if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed"); unlock_creation(); return res; }
/* Write to a file either from user space */ int msdos_file_write( struct inode *inode, struct file *filp, const char *buf, int count) { struct super_block *sb = inode->i_sb; int sector,offset,size,left,written; int error,carry; char *start,*to,ch; struct buffer_head *bh; int binary_mode = MSDOS_I(inode)->i_binary; if (!inode) { printk("msdos_file_write: inode = NULL\n"); return -EINVAL; } /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) { printk("msdos_file_write: mode = %07o\n",inode->i_mode); return -EINVAL; } /* * ok, append may not work when many processes are writing at the same time * but so what. That way leads to madness anyway. */ if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size; if (count <= 0) return 0; error = carry = 0; for (start = (char *)buf; count || carry; count -= size) { while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS))) if ((error = msdos_add_cluster(inode)) < 0) break; if (error) { msdos_truncate(inode); break; } offset = filp->f_pos & (SECTOR_SIZE-1); size = MIN(SECTOR_SIZE-offset,MAX(carry,count)); if (binary_mode && offset == 0 && (size == SECTOR_SIZE || filp->f_pos + size >= inode->i_size)){ /* No need to read the block first since we will */ /* completely overwrite it */ /* or at least write past the end of file */ if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){ error = -EIO; break; } }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) { error = -EIO; break; } if (binary_mode) { memcpy_fromfs(bh->b_data+offset,buf,written = size); buf += size; } else { written = left = SECTOR_SIZE-offset; to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1)); if (carry) { *to++ = '\n'; left--; carry = 0; } for (size = 0; size < count && left; size++) { if ((ch = get_fs_byte(buf++)) == '\n') { *to++ = '\r'; left--; } if (!left) carry = 1; else { *to++ = ch; left--; } } written -= left; } filp->f_pos += written; if (filp->f_pos > inode->i_size) { inode->i_size = filp->f_pos; inode->i_dirt = 1; } msdos_set_uptodate(sb,bh,1); mark_buffer_dirty(bh, 0); brelse(bh); } if (start == buf) return error; inode->i_mtime = inode->i_ctime = FS_CURRENT_TIME; MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_dirt = 1; return buf-start; }