PageRenderTime 55ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/newcnix/cnix-experimental/fs/write.c

http://newcnix.googlecode.com/
C | 342 lines | 268 code | 66 blank | 8 comment | 54 complexity | d00d87d052472ed58b80b3d1f273b1e3 MD5 | raw file
  1. #include <cnix/string.h>
  2. #include <cnix/errno.h>
  3. #include <cnix/devices.h>
  4. #include <cnix/fs.h>
  5. #include <cnix/kernel.h>
  6. #include <asm/system.h>
  7. #include "ext2/ext2.h"
  8. static ssize_t dev_write(
  9. struct inode * inoptr,
  10. const char * buffer,
  11. size_t count,
  12. off_t pos,
  13. int * error,
  14. int flags
  15. )
  16. {
  17. dev_t dev;
  18. ssize_t writed;
  19. writed = 0;
  20. dev = inoptr->i_ops->realdev(inoptr);
  21. if(MAJOR(dev) < get_dev_nr() && dev_table[MAJOR(dev)].write)
  22. writed = dev_table[MAJOR(dev)].write(
  23. MINOR(dev),
  24. buffer,
  25. count,
  26. pos,
  27. error,
  28. flags
  29. );
  30. return writed;
  31. }
  32. extern ssize_t socket_write(
  33. struct inode * inoptr,
  34. const char * buffer,
  35. size_t count,
  36. int * error,
  37. int falgs
  38. );
  39. ssize_t do_write(int fd, const char * buffer, size_t count)
  40. {
  41. int ret, error = 0;
  42. off_t pos, inblock;
  43. unsigned long block;
  44. ssize_t writed, writing;
  45. struct filp * fp;
  46. struct inode * inoptr;
  47. struct buf_head * bh;
  48. unsigned long flags;
  49. mode_t mode;
  50. int blocksize;
  51. struct super_block * sb;
  52. fp = fget(fd);
  53. if(!fp)
  54. DIE("BUG: cannot happen\n");
  55. if(count < 0)
  56. DIE("BUG: cannot happen\n");
  57. if(!count)
  58. return 0;
  59. if((fp->f_mode & O_ACCMODE) == O_RDONLY)
  60. return -EINVAL;
  61. writed = 0;
  62. inoptr = fp->f_ino;
  63. if(is_socket(inoptr)){
  64. writed = socket_write(
  65. inoptr,
  66. buffer,
  67. count,
  68. &error,
  69. fp->f_mode | current->fflags[fd]
  70. );
  71. if(error < 0)
  72. return error;
  73. return writed;
  74. }
  75. if(is_pipe(inoptr)){
  76. int writep, count1;
  77. unsigned char * ibuffer;
  78. count1 = count;
  79. check_again:
  80. if(!inoptr->i_buddy){
  81. sendsig(current, SIGPIPE);
  82. return -EPIPE;
  83. }
  84. if(inoptr->i_pipesize >= 4096){
  85. lockb_all(flags);
  86. current->sleep_spot = &inoptr->i_wait;
  87. sleepon(&inoptr->i_wait);
  88. if(anysig(current)){
  89. unlockb_all(flags);
  90. return -EINTR;
  91. }
  92. unlockb_all(flags);
  93. goto check_again;
  94. }
  95. if(count > 4096 - inoptr->i_pipesize)
  96. count = 4096 - inoptr->i_pipesize;
  97. writep = inoptr->i_writep;
  98. ibuffer = inoptr->i_buffer;
  99. while(count > 0){
  100. writing = 4096 - writep;
  101. if(writing > count)
  102. writing = count;
  103. ret = memcpy_from_user(
  104. &ibuffer[writep], &buffer[writed], writing
  105. );
  106. if(ret < 0){
  107. wakeup(&inoptr->i_wait);
  108. select_wakeup(&inoptr->i_select, OPTYPE_READ);
  109. return -EFAULT;
  110. }
  111. writep += writing;
  112. if(writep >= 4096)
  113. writep = 0;
  114. inoptr->i_writep = writep;
  115. inoptr->i_pipesize += writing;
  116. writed += writing;
  117. count -= writing;
  118. }
  119. wakeup(&inoptr->i_wait);
  120. select_wakeup(&inoptr->i_select, OPTYPE_READ);
  121. if(writed < count1){
  122. count = count1 - writed;
  123. goto check_again;
  124. }
  125. return writed;
  126. }
  127. mode = inoptr->i_ops->mode(inoptr);
  128. if(S_ISDIR(mode))
  129. return -EISDIR;
  130. if(S_ISBLK(mode) || S_ISCHR(mode)){
  131. writed = dev_write(
  132. inoptr,
  133. buffer,
  134. count,
  135. fp->f_pos,
  136. &error,
  137. fp->f_mode | current->fflags[fd]
  138. );
  139. fp->f_pos += writed;
  140. if(error < 0)
  141. return error;
  142. return writed;
  143. }else if(S_ISFIFO(mode)){
  144. inoptr->i_count++;
  145. iput(inoptr);
  146. return -EINVAL;
  147. }
  148. sb = inoptr->i_sb;
  149. pos = fp->f_pos;
  150. blocksize = inoptr->i_ops->blocksize(inoptr);
  151. inblock = pos % blocksize;
  152. if(inblock){
  153. if(pos >= inoptr->i_ops->max_filesize(inoptr))
  154. return -EFBIG;
  155. writing = blocksize - inblock;
  156. if(writing > count)
  157. writing = count;
  158. block = inoptr->i_ops->bmap(inoptr, pos);
  159. if(block == NOBLK){
  160. // xxx: error if block size is not equal to zone
  161. block = sb->s_filesystem->balloc(sb);
  162. if(block == NOBLK){
  163. printk("out of disk space\n");
  164. goto errout;
  165. }
  166. bh = getblk(inoptr->i_dev, block, blocksize);
  167. if(!bh){
  168. sb->s_filesystem->bfree(sb, block);
  169. goto errout;
  170. }
  171. memset(bh->b_data, 0, blocksize);
  172. if(!inoptr->i_ops->minode(inoptr, pos, block)){
  173. sb->s_filesystem->bfree(sb, block);
  174. brelse(bh);
  175. goto errout;
  176. }
  177. }else{
  178. bh = sd_bread(inoptr->i_dev, block*EXT2_BLOCK_GRAN);
  179. if(!bh)
  180. goto errout;
  181. }
  182. ret = memcpy_from_user(&bh->b_data[inblock], buffer, writing);
  183. if(ret < 0){
  184. brelse(bh);
  185. return -EFAULT;
  186. }
  187. if(fp->f_mode & O_SYNC){ // xxx: need test
  188. bwrite(bh);
  189. brelse(bh);
  190. }else{
  191. bh->b_flags |= B_DIRTY | B_DONE; // delay write
  192. brelse(bh);
  193. }
  194. writed += writing;
  195. pos += writing;
  196. if(pos > inoptr->i_ops->size(inoptr))
  197. inoptr->i_ops->setsize(inoptr, pos);
  198. }
  199. //if(pos == 49152)
  200. // printk("here is the fish: writed: %d count: %d\n",writed,count);
  201. while(writed < count){
  202. if(pos >= inoptr->i_ops->max_filesize(inoptr))
  203. return -EFBIG;
  204. if((count - writed) > blocksize)
  205. writing = blocksize;
  206. else
  207. writing = count - writed;
  208. block = inoptr->i_ops->bmap(inoptr, pos);
  209. //if(pos==49152)
  210. // printk("where is the fish? ino: %x block: %u\n",fp->f_ino,block);
  211. if(block == NOBLK){
  212. // xxx: error if block size is not equal to zone
  213. block = sb->s_filesystem->balloc(sb);
  214. if(block == NOBLK){
  215. printk("out of disk space\n");
  216. goto errout;
  217. }
  218. bh = getblk(inoptr->i_dev, block, blocksize);
  219. if(!bh){
  220. sb->s_filesystem->bfree(sb, block);
  221. goto errout;
  222. }
  223. memset(bh->b_data, 0, blocksize);
  224. if(!inoptr->i_ops->minode(inoptr, pos, block)){
  225. sb->s_filesystem->bfree(sb, block);
  226. brelse(bh);
  227. goto errout;
  228. }
  229. }else{
  230. bh = sd_bread(inoptr->i_dev, block*EXT2_BLOCK_GRAN);
  231. if(!bh)
  232. goto errout;
  233. }
  234. ret = memcpy_from_user(bh->b_data, &buffer[writed], writing);
  235. if(ret < 0){
  236. brelse(bh);
  237. return -EFAULT;
  238. }
  239. //if(pos == 49152)
  240. // printk("buf: %x first bytes: %x\n",bh->b_data,*(unsigned*)(bh->b_data));
  241. if(fp->f_mode & O_SYNC){ // xxx: need test
  242. bwrite(bh);
  243. brelse(bh);
  244. }else{
  245. bh->b_flags |= B_DIRTY | B_DONE; // delay write
  246. brelse(bh);
  247. }
  248. writed += writing;
  249. pos += writing;
  250. if(pos > inoptr->i_ops->size(inoptr))
  251. inoptr->i_ops->setsize(inoptr, pos);
  252. }
  253. fp->f_pos = pos;
  254. if(pos > inoptr->i_ops->size(inoptr))
  255. inoptr->i_ops->setsize(inoptr, pos);
  256. if (S_ISREG(mode) || S_ISDIR(mode))
  257. {
  258. inoptr->i_update |= MTIME;
  259. inoptr->i_dirty = 1;
  260. }
  261. inoptr->i_count++;
  262. iput(inoptr);
  263. return writed;
  264. errout:
  265. fp->f_pos = pos;
  266. if(pos > inoptr->i_ops->size(inoptr))
  267. inoptr->i_ops->setsize(inoptr, pos);
  268. if (S_ISREG(mode) || S_ISDIR(mode))
  269. {
  270. inoptr->i_update |= MTIME;
  271. inoptr->i_dirty = 1;
  272. }
  273. inoptr->i_count++;
  274. iput(inoptr);
  275. return -EIO;
  276. }