今天一个同事问我关于write(2)在写入文件的时候问题,问题是这样的:
当磁盘剩余空间不能将一次write调用希望写入的数据写完的时候,write是直接返回-1,然后设置errno为ENOSPC,还是先写入一部分数据,将剩余空间占满然后再下一次调用的时候返回错误?
当时发现好像没有考虑过这样的问题,Google了一下,好像没有找到关于这个细节的说明。
于是今天决定自己试试看。用dd建立一个64M大小的文件,然后弄上不同的文件系统用loop挂载,去写满试试看。
测试程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <stdbool.h> #define BUF_LEN 2011 static unsigned short src_buff[BUF_LEN]; static void init_buf(unsigned short *buff) { int i; for (i = 0; i < BUF_LEN; i++) buff[i] = i; /* 缓冲区每个数据内容都唯一 */ } static bool add_data(int fd, unsigned short **buff, size_t cnt) { ssize_t err; off_t cur_pos, last_pos; bool ret = true; last_pos = lseek(fd, 0, SEEK_CUR); printf("the first data is %hun", **buff); err = write(fd, *buff, cnt * sizeof(**buff)); if (err < 0) { perror("write error"); ret = false; } else if (err == 0) { perror("File tail"); } else { *buff += err / sizeof(**buff); /* 必须写入完整的buff元素 */ } cur_pos = lseek(fd, -1 * (err % sizeof(**buff)), SEEK_CUR); /* 抛弃不完整的写入 */ printf("the last data is %hun", *(*buff - 1)); printf("return value = %zd,n", err); printf("the file offset is %lld to %lldn", (long long int)last_pos, (long long int)cur_pos); printf("n"); return ret; } int main(int argc, char *argv[]) { unsigned short *buf_pos = src_buff; int fd; char *filename = "test.dat"; if (argc == 2) { filename = argv[1]; } /* 默认打开的文件 */ fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0644); if (fd == -1) { perror("open failure"); goto err; } init_buf(src_buff); do { if (buf_pos - src_buff >= BUF_LEN) buf_pos = src_buff; } while (add_data(fd, &buf_pos, src_buff + BUF_LEN - buf_pos)); return EXIT_SUCCESS; err: return EXIT_FAILURE; } |
然后测试,结束前的输出如下。
reiserfs下:
the first data is 0
the last data is 2010
return value = 4022,
the file offset is 33430864 to 33434886
the first data is 0
the last data is 380
return value = 762,
the file offset is 33434886 to 33435648
the first data is 381
write error: No space left on device
the last data is 380
return value = -1,
the file offset is 33435648 to 33435647
the last data is 2010
return value = 4022,
the file offset is 33430864 to 33434886
the first data is 0
the last data is 380
return value = 762,
the file offset is 33434886 to 33435648
the first data is 381
write error: No space left on device
the last data is 380
return value = -1,
the file offset is 33435648 to 33435647
ext4下:
the first data is 0
the last data is 2010
return value = 4022,
the file offset is 59461248 to 59465270
the first data is 0
the last data is 228
return value = 458,
the file offset is 59465270 to 59465728
the first data is 229
write error: No space left on device
the last data is 228
return value = -1,
the file offset is 59465728 to 59465727
the last data is 2010
return value = 4022,
the file offset is 59461248 to 59465270
the first data is 0
the last data is 228
return value = 458,
the file offset is 59465270 to 59465728
the first data is 229
write error: No space left on device
the last data is 228
return value = -1,
the file offset is 59465728 to 59465727
jfs下:
the first data is 0
the last data is 2010
return value = 4022,
the file offset is 65699370 to 65703392
the first data is 0
the last data is 271
return value = 544,
the file offset is 65703392 to 65703936
the first data is 272
write error: No space left on device
the last data is 271
return value = -1,
the file offset is 65703936 to 65703935
the last data is 2010
return value = 4022,
the file offset is 65699370 to 65703392
the first data is 0
the last data is 271
return value = 544,
the file offset is 65703392 to 65703936
the first data is 272
write error: No space left on device
the last data is 271
return value = -1,
the file offset is 65703936 to 65703935
xfs下:
the first data is 0
the last data is 2010
return value = 4022,
the file offset is 58648804 to 58652826
the first data is 0
the last data is 946
return value = 1894,
the file offset is 58652826 to 58654720
the first data is 947
write error: No space left on device
the last data is 946
return value = -1,
the file offset is 58654720 to 58654719
the last data is 2010
return value = 4022,
the file offset is 58648804 to 58652826
the first data is 0
the last data is 946
return value = 1894,
the file offset is 58652826 to 58654720
the first data is 947
write error: No space left on device
the last data is 946
return value = -1,
the file offset is 58654720 to 58654719
ntfs-3g:
the first data is 0
the last data is 2010
return value = 4022,
the file offset is 64488748 to 64492770
the first data is 0
the last data is 1422
return value = 2846,
the file offset is 64492770 to 64495616
the first data is 1423
write error: No space left on device
the last data is 1422
return value = -1,
the file offset is 64495616 to 64495615
the last data is 2010
return value = 4022,
the file offset is 64488748 to 64492770
the first data is 0
the last data is 1422
return value = 2846,
the file offset is 64492770 to 64495616
the first data is 1423
write error: No space left on device
the last data is 1422
return value = -1,
the file offset is 64495616 to 64495615
vfat下:
the first data is 0
the last data is 2010
return value = 4022,
the file offset is 66950212 to 66954234
the first data is 0
the last data is 2010
return value = 4022,
the file offset is 66954234 to 66958256
the first data is 0
write error: No space left on device
the last data is 0
return value = -1,
the file offset is 66958256 to 66958255
the last data is 2010
return value = 4022,
the file offset is 66950212 to 66954234
the first data is 0
the last data is 2010
return value = 4022,
the file offset is 66954234 to 66958256
the first data is 0
write error: No space left on device
the last data is 0
return value = -1,
the file offset is 66958256 to 66958255
貌似除了vfat以外,都是尽量将磁盘写满。但是vfat只要空间不够,就立即返回错误了。
不知道这个特性是什么标准规定的?或者是没有规定的?