aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/fat/dir.c6
-rw-r--r--fs/fat/fat.h7
-rw-r--r--fs/fat/inode.c34
-rw-r--r--fs/fat/misc.c148
-rw-r--r--fs/fat/namei_msdos.c2
-rw-r--r--fs/fat/namei_vfat.c5
6 files changed, 130 insertions, 72 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 08b23ad25f1c..a601c6d45bc0 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -1089,6 +1089,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
1089 struct msdos_dir_entry *de; 1089 struct msdos_dir_entry *de;
1090 sector_t blknr; 1090 sector_t blknr;
1091 __le16 date, time; 1091 __le16 date, time;
1092 u8 time_cs;
1092 int err, cluster; 1093 int err, cluster;
1093 1094
1094 err = fat_alloc_clusters(dir, &cluster, 1); 1095 err = fat_alloc_clusters(dir, &cluster, 1);
@@ -1102,7 +1103,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
1102 goto error_free; 1103 goto error_free;
1103 } 1104 }
1104 1105
1105 fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); 1106 fat_time_unix2fat(sbi, ts, &time, &date, &time_cs);
1106 1107
1107 de = (struct msdos_dir_entry *)bhs[0]->b_data; 1108 de = (struct msdos_dir_entry *)bhs[0]->b_data;
1108 /* filling the new directory slots ("." and ".." entries) */ 1109 /* filling the new directory slots ("." and ".." entries) */
@@ -1112,13 +1113,14 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts)
1112 de[0].lcase = de[1].lcase = 0; 1113 de[0].lcase = de[1].lcase = 0;
1113 de[0].time = de[1].time = time; 1114 de[0].time = de[1].time = time;
1114 de[0].date = de[1].date = date; 1115 de[0].date = de[1].date = date;
1115 de[0].ctime_cs = de[1].ctime_cs = 0;
1116 if (sbi->options.isvfat) { 1116 if (sbi->options.isvfat) {
1117 /* extra timestamps */ 1117 /* extra timestamps */
1118 de[0].ctime = de[1].ctime = time; 1118 de[0].ctime = de[1].ctime = time;
1119 de[0].ctime_cs = de[1].ctime_cs = time_cs;
1119 de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date; 1120 de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date;
1120 } else { 1121 } else {
1121 de[0].ctime = de[1].ctime = 0; 1122 de[0].ctime = de[1].ctime = 0;
1123 de[0].ctime_cs = de[1].ctime_cs = 0;
1122 de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; 1124 de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0;
1123 } 1125 }
1124 de[0].start = cpu_to_le16(cluster); 1126 de[0].start = cpu_to_le16(cluster);
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 51f1c42ca5e3..a2a570f81719 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -263,9 +263,10 @@ extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
263extern void fat_fs_panic(struct super_block *s, const char *fmt, ...); 263extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
264extern void fat_clusters_flush(struct super_block *sb); 264extern void fat_clusters_flush(struct super_block *sb);
265extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); 265extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
266extern int date_dos2unix(unsigned short time, unsigned short date, int tz_utc); 266extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
267extern void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date, 267 __le16 __time, __le16 __date, u8 time_cs);
268 int tz_utc); 268extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
269 __le16 *time, __le16 *date, u8 *time_cs);
269extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); 270extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
270 271
271int fat_cache_init(void); 272int fat_cache_init(void);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 3921de2013a4..079d9d5e0d36 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -381,22 +381,12 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
381 MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED; 381 MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
382 inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) 382 inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
383 & ~((loff_t)sbi->cluster_size - 1)) >> 9; 383 & ~((loff_t)sbi->cluster_size - 1)) >> 9;
384 inode->i_mtime.tv_sec = 384
385 date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date), 385 fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
386 sbi->options.tz_utc);
387 inode->i_mtime.tv_nsec = 0;
388 if (sbi->options.isvfat) { 386 if (sbi->options.isvfat) {
389 int secs = de->ctime_cs / 100; 387 fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
390 int csecs = de->ctime_cs % 100; 388 de->cdate, de->ctime_cs);
391 inode->i_ctime.tv_sec = 389 fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
392 date_dos2unix(le16_to_cpu(de->ctime),
393 le16_to_cpu(de->cdate),
394 sbi->options.tz_utc) + secs;
395 inode->i_ctime.tv_nsec = csecs * 10000000;
396 inode->i_atime.tv_sec =
397 date_dos2unix(0, le16_to_cpu(de->adate),
398 sbi->options.tz_utc);
399 inode->i_atime.tv_nsec = 0;
400 } else 390 } else
401 inode->i_ctime = inode->i_atime = inode->i_mtime; 391 inode->i_ctime = inode->i_atime = inode->i_mtime;
402 392
@@ -591,16 +581,14 @@ retry:
591 raw_entry->attr = fat_attr(inode); 581 raw_entry->attr = fat_attr(inode);
592 raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); 582 raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart);
593 raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); 583 raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16);
594 fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, 584 fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time,
595 &raw_entry->date, sbi->options.tz_utc); 585 &raw_entry->date, NULL);
596 if (sbi->options.isvfat) { 586 if (sbi->options.isvfat) {
597 __le16 atime; 587 __le16 atime;
598 fat_date_unix2dos(inode->i_ctime.tv_sec, &raw_entry->ctime, 588 fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
599 &raw_entry->cdate, sbi->options.tz_utc); 589 &raw_entry->cdate, &raw_entry->ctime_cs);
600 fat_date_unix2dos(inode->i_atime.tv_sec, &atime, 590 fat_time_unix2fat(sbi, &inode->i_atime, &atime,
601 &raw_entry->adate, sbi->options.tz_utc); 591 &raw_entry->adate, NULL);
602 raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 +
603 inode->i_ctime.tv_nsec / 10000000;
604 } 592 }
605 spin_unlock(&sbi->inode_hash_lock); 593 spin_unlock(&sbi->inode_hash_lock);
606 mark_buffer_dirty(bh); 594 mark_buffer_dirty(bh);
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 91ad9be18ff9..a191e79e66a9 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -135,65 +135,131 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
135 135
136extern struct timezone sys_tz; 136extern struct timezone sys_tz;
137 137
138/*
139 * The epoch of FAT timestamp is 1980.
140 * : bits : value
141 * date: 0 - 4: day (1 - 31)
142 * date: 5 - 8: month (1 - 12)
143 * date: 9 - 15: year (0 - 127) from 1980
144 * time: 0 - 4: sec (0 - 29) 2sec counts
145 * time: 5 - 10: min (0 - 59)
146 * time: 11 - 15: hour (0 - 23)
147 */
148#define SECS_PER_MIN 60
149#define SECS_PER_HOUR (60 * 60)
150#define SECS_PER_DAY (SECS_PER_HOUR * 24)
151#define UNIX_SECS_1980 315532800L
152#if BITS_PER_LONG == 64
153#define UNIX_SECS_2108 4354819200L
154#endif
155/* days between 1.1.70 and 1.1.80 (2 leap days) */
156#define DAYS_DELTA (365 * 10 + 2)
157/* 120 (2100 - 1980) isn't leap year */
158#define YEAR_2100 120
159#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100)
160
138/* Linear day numbers of the respective 1sts in non-leap years. */ 161/* Linear day numbers of the respective 1sts in non-leap years. */
139static int day_n[] = { 162static time_t days_in_year[] = {
140 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 163 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
141 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 164 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
142}; 165};
143 166
144/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ 167/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
145int date_dos2unix(unsigned short time, unsigned short date, int tz_utc) 168void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
169 __le16 __time, __le16 __date, u8 time_cs)
146{ 170{
147 int month, year, secs; 171 u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date);
172 time_t second, day, leap_day, month, year;
148 173
149 /* 174 year = date >> 9;
150 * first subtract and mask after that... Otherwise, if 175 month = max(1, (date >> 5) & 0xf);
151 * date == 0, bad things happen 176 day = max(1, date & 0x1f) - 1;
152 */ 177
153 month = ((date >> 5) - 1) & 15; 178 leap_day = (year + 3) / 4;
154 year = date >> 9; 179 if (year > YEAR_2100) /* 2100 isn't leap year */
155 secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* 180 leap_day--;
156 ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && 181 if (IS_LEAP_YEAR(year) && month > 2)
157 month < 2 ? 1 : 0)+3653); 182 leap_day++;
158 /* days since 1.1.70 plus 80's leap day */ 183
159 if (!tz_utc) 184 second = (time & 0x1f) << 1;
160 secs += sys_tz.tz_minuteswest*60; 185 second += ((time >> 5) & 0x3f) * SECS_PER_MIN;
161 return secs; 186 second += (time >> 11) * SECS_PER_HOUR;
187 second += (year * 365 + leap_day
188 + days_in_year[month] + day
189 + DAYS_DELTA) * SECS_PER_DAY;
190
191 if (!sbi->options.tz_utc)
192 second += sys_tz.tz_minuteswest * SECS_PER_MIN;
193
194 if (time_cs) {
195 ts->tv_sec = second + (time_cs / 100);
196 ts->tv_nsec = (time_cs % 100) * 10000000;
197 } else {
198 ts->tv_sec = second;
199 ts->tv_nsec = 0;
200 }
162} 201}
163 202
164/* Convert linear UNIX date to a MS-DOS time/date pair. */ 203/* Convert linear UNIX date to a FAT time/date pair. */
165void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date, int tz_utc) 204void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
205 __le16 *time, __le16 *date, u8 *time_cs)
166{ 206{
167 int day, year, nl_day, month; 207 time_t second = ts->tv_sec;
208 time_t day, leap_day, month, year;
168 209
169 if (!tz_utc) 210 if (!sbi->options.tz_utc)
170 unix_date -= sys_tz.tz_minuteswest*60; 211 second -= sys_tz.tz_minuteswest * SECS_PER_MIN;
171 212
172 /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ 213 /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
173 if (unix_date < 315532800) 214 if (second < UNIX_SECS_1980) {
174 unix_date = 315532800; 215 *time = 0;
175 216 *date = cpu_to_le16((0 << 9) | (1 << 5) | 1);
176 *time = cpu_to_le16((unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ 217 if (time_cs)
177 (((unix_date/3600) % 24) << 11)); 218 *time_cs = 0;
178 day = unix_date/86400-3652; 219 return;
179 year = day/365; 220 }
180 if ((year+3)/4+365*year > day) 221#if BITS_PER_LONG == 64
222 if (second >= UNIX_SECS_2108) {
223 *time = cpu_to_le16((23 << 11) | (59 << 5) | 29);
224 *date = cpu_to_le16((127 << 9) | (12 << 5) | 31);
225 if (time_cs)
226 *time_cs = 199;
227 return;
228 }
229#endif
230
231 day = second / SECS_PER_DAY - DAYS_DELTA;
232 year = day / 365;
233 leap_day = (year + 3) / 4;
234 if (year > YEAR_2100) /* 2100 isn't leap year */
235 leap_day--;
236 if (year * 365 + leap_day > day)
181 year--; 237 year--;
182 day -= (year+3)/4+365*year; 238 leap_day = (year + 3) / 4;
183 if (day == 59 && !(year & 3)) { 239 if (year > YEAR_2100) /* 2100 isn't leap year */
184 nl_day = day; 240 leap_day--;
241 day -= year * 365 + leap_day;
242
243 if (IS_LEAP_YEAR(year) && day == days_in_year[3]) {
185 month = 2; 244 month = 2;
186 } else { 245 } else {
187 nl_day = (year & 3) || day <= 59 ? day : day-1; 246 if (IS_LEAP_YEAR(year) && day > days_in_year[3])
188 for (month = 0; month < 12; month++) { 247 day--;
189 if (day_n[month] > nl_day) 248 for (month = 1; month < 12; month++) {
249 if (days_in_year[month + 1] > day)
190 break; 250 break;
191 } 251 }
192 } 252 }
193 *date = cpu_to_le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9)); 253 day -= days_in_year[month];
194}
195 254
196EXPORT_SYMBOL_GPL(fat_date_unix2dos); 255 *time = cpu_to_le16(((second / SECS_PER_HOUR) % 24) << 11
256 | ((second / SECS_PER_MIN) % 60) << 5
257 | (second % SECS_PER_MIN) >> 1);
258 *date = cpu_to_le16((year << 9) | (month << 5) | (day + 1));
259 if (time_cs)
260 *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000;
261}
262EXPORT_SYMBOL_GPL(fat_time_unix2fat);
197 263
198int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) 264int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
199{ 265{
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index c0a4d5cd99b2..e92e8158ebaf 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -247,7 +247,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
247 if (is_hid) 247 if (is_hid)
248 de.attr |= ATTR_HIDDEN; 248 de.attr |= ATTR_HIDDEN;
249 de.lcase = 0; 249 de.lcase = 0;
250 fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); 250 fat_time_unix2fat(sbi, ts, &time, &date, NULL);
251 de.cdate = de.adate = 0; 251 de.cdate = de.adate = 0;
252 de.ctime = 0; 252 de.ctime = 0;
253 de.ctime_cs = 0; 253 de.ctime_cs = 0;
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index facf3bf0211a..1536bc3ca0f0 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -568,6 +568,7 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name,
568 unsigned char msdos_name[MSDOS_NAME]; 568 unsigned char msdos_name[MSDOS_NAME];
569 wchar_t *uname; 569 wchar_t *uname;
570 __le16 time, date; 570 __le16 time, date;
571 u8 time_cs;
571 int err, ulen, usize, i; 572 int err, ulen, usize, i;
572 loff_t offset; 573 loff_t offset;
573 574
@@ -620,10 +621,10 @@ shortname:
620 memcpy(de->name, msdos_name, MSDOS_NAME); 621 memcpy(de->name, msdos_name, MSDOS_NAME);
621 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; 622 de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
622 de->lcase = lcase; 623 de->lcase = lcase;
623 fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); 624 fat_time_unix2fat(sbi, ts, &time, &date, &time_cs);
624 de->time = de->ctime = time; 625 de->time = de->ctime = time;
625 de->date = de->cdate = de->adate = date; 626 de->date = de->cdate = de->adate = date;
626 de->ctime_cs = 0; 627 de->ctime_cs = time_cs;
627 de->start = cpu_to_le16(cluster); 628 de->start = cpu_to_le16(cluster);
628 de->starthi = cpu_to_le16(cluster >> 16); 629 de->starthi = cpu_to_le16(cluster >> 16);
629 de->size = 0; 630 de->size = 0;