~ubuntu-branches/ubuntu/precise/arj/precise-security

« back to all changes in this revision

Viewing changes to arjtypes.c

  • Committer: Bazaar Package Importer
  • Author(s): Guillem Jover
  • Date: 2004-06-27 08:07:09 UTC
  • Revision ID: james.westby@ubuntu.com-20040627080709-1gkxm72ex66gkwe4
Tags: upstream-3.10.21
ImportĀ upstreamĀ versionĀ 3.10.21

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: arjtypes.c,v 1.7 2004/06/18 16:19:37 andrew_belov Exp $
 
3
 * ---------------------------------------------------------------------------
 
4
 * This module provides some multiplatform property types which cover both DOS
 
5
 * (as internally involved in ARJ) and UNIX requirements.
 
6
 *
 
7
 */
 
8
 
 
9
#include <time.h>
 
10
 
 
11
#include "arj.h"
 
12
 
 
13
DEBUGHDR(__FILE__)                      /* Debug information block */
 
14
 
 
15
/* Timestamp macros */
 
16
 
 
17
#define get_tx(m,d,h,n) (((unsigned long)(m)<<21)+((unsigned long)(d)<<16)+((unsigned long)(h)<<11)+((n)<<5))
 
18
#define get_tstamp(y,m,d,h,n,s) ((((unsigned long)((y)-1980))<<25)+get_tx((m),(d),(h),(n))+((s)/2))
 
19
 
 
20
#define ts_year(ts)  ((unsigned int)(((ts)>>25)&0x7f)+1980)
 
21
#define ts_month(ts) ((unsigned int)((ts)>>21)&0x0f)  /* 1..12 means Jan..Dec */
 
22
#define ts_day(ts)   ((unsigned int)((ts)>>16)&0x1f)  /* 1..31 means 1st..31st */
 
23
#define ts_hour(ts)  ((unsigned int)((ts)>>11)&0x1f)
 
24
#define ts_min(ts)   ((unsigned int)((ts)>>5)&0x3f)
 
25
#define ts_sec(ts)   ((unsigned int)(((ts)&0x1f)*2))
 
26
 
 
27
static char monthdays[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
28
 
 
29
/* Q&D helper macro */
 
30
 
 
31
#define is_unix(host_os) (host_os==OS_UNIX||host_os==OS_NEXT)
 
32
 
 
33
/* Timestamp storage structures */
 
34
 
 
35
#if SFX_LEVEL>=ARJSFX
 
36
 static char time_list_format[]="%04u-%02u-%02u %02u:%02u:%02u";
 
37
#endif
 
38
 
 
39
/*
 
40
 * File mode routines
 
41
 */
 
42
 
 
43
/* Parses a file mode specifier from the archive. The idea is to allow
 
44
   creation of DOS attributes under UNIX, but no features exist for
 
45
   DOS->UNIX conversion. */
 
46
 
 
47
void fm_store(struct file_mode *dest, int host_os, int mode)
 
48
{
 
49
 if(host_os==OS_SPECIAL)
 
50
  dest->dos=dest->native=mode;
 
51
 if(is_unix(OS))
 
52
 {
 
53
  dest->native=mode;
 
54
  dest->dos=FATTR_ARCH;
 
55
  if(is_unix(OS)&&!(mode&FATTR_IWUSR))
 
56
   dest->dos|=FATTR_RDONLY;
 
57
 }
 
58
 else                                   /* Assume a DOS-style system */
 
59
  dest->dos=dest->native=mode;
 
60
}
 
61
 
 
62
/* Retrieves a native file mode corresponding to the host OS */
 
63
 
 
64
unsigned int fm_native(struct file_mode *fm, int host_os)
 
65
{
 
66
 return(is_unix(host_os)?fm->native:fm->dos);
 
67
}
 
68
 
 
69
/*
 
70
 * Timestamp routines
 
71
 */
 
72
 
 
73
/* Returns 1 if there's a leap year */
 
74
 
 
75
static int isleapyear(int year)
 
76
{
 
77
 if(year%400==0)
 
78
  return(1);
 
79
 if(year%100==0)
 
80
  return(0);
 
81
 if(year%4==0)
 
82
  return(1);
 
83
 return(0);
 
84
}
 
85
 
 
86
/* A "home-brew" implemenation of localtime(). This is for cases when we have a TZ_VAR
 
87
   of our own. */
 
88
 
 
89
#ifdef TZ_VAR
 
90
static struct tm *ununixtime(unsigned long *pt)
 
91
#define localtime(t) ununixtime((unsigned long *)(t))
 
92
{
 
93
 unsigned long unixtime, timepart;
 
94
 int year, month, mdays;
 
95
 static struct tm stm;
 
96
 
 
97
 unixtime=*pt-TZ_VAR;
 
98
 if(_daylight)
 
99
  unixtime+=3600;
 
100
 timepart=unixtime%86400L; unixtime/=86400L;
 
101
 for(year=1970; 365+isleapyear(year)<=unixtime; year++)
 
102
  unixtime-=365+isleapyear(year);
 
103
 stm.tm_year=year-1900;
 
104
 month=0;
 
105
 while(1)
 
106
 {
 
107
  if(month==1)
 
108
   mdays=isleapyear(year)?29:28;
 
109
  else
 
110
   mdays=monthdays[month];
 
111
  if(mdays>unixtime||month==11)
 
112
   break;
 
113
  unixtime-=mdays;
 
114
  month++;
 
115
 }
 
116
 stm.tm_mon=month;
 
117
 stm.tm_mday=unixtime+1;
 
118
 stm.tm_hour=timepart/3600;
 
119
 stm.tm_min=timepart/60%60;
 
120
 stm.tm_sec=timepart%60;
 
121
 return(&stm);
 
122
}
 
123
#endif
 
124
 
 
125
/* Converts a UNIX timestamp to the DOS style */
 
126
 
 
127
static unsigned long ts_unix2dos(const long ts)
 
128
{
 
129
 struct tm *stm;
 
130
 
 
131
 stm=localtime((time_t*)&ts);
 
132
 return(get_tstamp(stm->tm_year+1900, stm->tm_mon+1, stm->tm_mday,
 
133
        stm->tm_hour, stm->tm_min, stm->tm_sec));
 
134
}
 
135
 
 
136
/* Creates a Unix timestamp from the given date and time */
 
137
 
 
138
static unsigned long mk_unixtime(int y, int m, int d, int hh, int mm, int ss)
 
139
{
 
140
 unsigned long u=0;
 
141
 int i;
 
142
 /* Clash with NetBSD/x86-64 patch: leaving rc as unsigned long still permits
 
143
    to escape the year 2038 problem in favor of year 2106 problem, while a
 
144
    dedicated time_t structure can be expected as a 64-bit value on relevant
 
145
    platforms -- ASR fix 25/01/2004 */
 
146
 unsigned long rc;
 
147
 time_t tt;
 
148
 long tzshift;
 
149
 #ifndef TZ_VAR
 
150
  long shiftd1, shiftd2;
 
151
 #endif
 
152
 struct tm *stm;
 
153
 
 
154
 if(y>=2001)
 
155
 {
 
156
  i=y-2001;
 
157
  u=11323;
 
158
  /* The following piece of code is rather paranoid in 16/32-bit world, where the
 
159
     timestamps are limited to year 2108. */
 
160
  #if defined(__32BIT__)||defined(TILED)
 
161
   if(i>=400)
 
162
   {
 
163
    u+=1022679L*(i/400);
 
164
    i%=400;
 
165
   }
 
166
  #endif
 
167
  if(i>=100)
 
168
  {
 
169
   u+=36524L*(i/100);
 
170
   i%=100;
 
171
  }
 
172
  u+=1461L*(i/4);
 
173
  u+=365L*(i%4);
 
174
 }
 
175
 else if(y>=1973)
 
176
  u=1096+(y-1973)/4*1461L+((y-1973)%4)*365L;
 
177
 else
 
178
  u=(y-1970)*365L;
 
179
 for(i=1; i<m; i++)
 
180
 {
 
181
  u+=(int)monthdays[i-1];
 
182
  if(i==2)
 
183
   u+=isleapyear(y);
 
184
 }
 
185
 rc=86400*(unsigned long)(u+d-1)+(unsigned long)hh*3600+(unsigned long)mm*60+(unsigned long)ss;
 
186
 /* If we have to use the timezone variable, do it now */
 
187
 #ifdef TZ_VAR
 
188
  tzshift=-TZ_VAR;
 
189
  if(_daylight)
 
190
   tzshift+=3600;
 
191
 #else
 
192
  tt=(time_t)rc;
 
193
  stm=localtime(&tt);
 
194
  debug_assert(stm!=NULL);              /* LIBCS.DLL returns NULL for unixtime beyond
 
195
                                           0x7FFFFFFF */
 
196
  tzshift=(long)stm->tm_hour*3600+(long)stm->tm_min*60;
 
197
  shiftd1=stm->tm_mday;
 
198
  stm=gmtime(&tt);
 
199
  debug_assert(stm!=NULL);
 
200
  shiftd2=stm->tm_mday;
 
201
  /* Local time overruns GMT, add 24 hours for safety */
 
202
  if(shiftd1<shiftd2&&shiftd1==1&&shiftd2>=28)
 
203
   tzshift+=86400;
 
204
  else if(shiftd1>shiftd2&&shiftd1>=28&&shiftd2==1)
 
205
   tzshift-=86400;
 
206
  else if(shiftd1>shiftd2)
 
207
   tzshift+=86400;
 
208
  else if(shiftd1<shiftd2)
 
209
   tzshift-=86400;
 
210
  tzshift-=(long)stm->tm_hour*3600+(long)stm->tm_min*60;
 
211
  tzshift%=86400;
 
212
 #endif
 
213
 /* Fix the timezone if it does not roll over the zero */
 
214
 return((tzshift>0&&rc<tzshift)?rc:rc-tzshift);
 
215
}
 
216
 
 
217
/* Converts a DOS timestamp to the UNIX representation */
 
218
 
 
219
static unsigned long ts_dos2unix(unsigned long ts)
 
220
{
 
221
 unsigned int y, m, d, hh, mm, ss;
 
222
 
 
223
 if(ts==0)
 
224
  return(0);
 
225
 y=ts_year(ts);
 
226
 m=ts_month(ts);
 
227
 d=ts_day(ts);
 
228
 hh=ts_hour(ts);
 
229
 mm=ts_min(ts);
 
230
 ss=ts_sec(ts);
 
231
 /* TODO: These assertions must be replaced by run-time check for incorrect timestamps
 
232
    like 31/15/2063 or 00/00/1980, since month array is 1...12 only. */
 
233
 #ifdef DEBUG
 
234
  debug_assert(m>=1&&m<=12);
 
235
  debug_assert(d>=1&&d<=31);
 
236
 #endif
 
237
 return(mk_unixtime(y, m, d, hh, mm, ss));
 
238
}
 
239
 
 
240
/* Stores a timestamp */
 
241
 
 
242
void ts_store(struct timestamp *dest, int host_os, unsigned long value)
 
243
{
 
244
 if(host_os==OS_SPECIAL)
 
245
  dest->dos=dest->unixtime=value;
 
246
 else if(is_unix(host_os))
 
247
 {
 
248
  dest->unixtime=value;
 
249
  dest->dos=ts_unix2dos(value);
 
250
 }
 
251
 else
 
252
 {
 
253
  dest->dos=value;
 
254
  dest->unixtime=ts_dos2unix(value);
 
255
 }
 
256
}
 
257
 
 
258
/* Retrieves a native timestamp corresponding to the host OS */
 
259
 
 
260
unsigned long ts_native(struct timestamp *ts, int host_os)
 
261
{
 
262
 return(is_unix(host_os)?ts->unixtime:ts->dos);
 
263
}
 
264
 
 
265
/* Compares two timestamps */
 
266
 
 
267
int ts_cmp(struct timestamp *ts1, struct timestamp *ts2)
 
268
{
 
269
 unsigned long tsn1, tsn2;
 
270
 
 
271
 tsn1=ts_native(ts1, OS);
 
272
 tsn2=ts_native(ts2, OS);
 
273
 if(tsn1<tsn2)
 
274
  return(-1);
 
275
 else if(tsn1==tsn2)
 
276
  return(0);
 
277
 else
 
278
  return(1);
 
279
}
 
280
 
 
281
#if SFX_LEVEL>=ARJ||defined(REARJ)
 
282
 
 
283
/* Produces an ARJ timestamp from the given date */
 
284
 
 
285
void make_timestamp(struct timestamp *dest, int y, int m, int d, int hh, int mm, int ss)
 
286
{
 
287
 dest->unixtime=mk_unixtime(y, m, d, hh, mm, ss);
 
288
 dest->dos=ts_unix2dos(dest->unixtime);
 
289
}
 
290
 
 
291
#endif
 
292
 
 
293
#if SFX_LEVEL>=ARJSFX
 
294
 
 
295
/* Restores the given timestamp to character form */
 
296
 
 
297
void timestamp_to_str(char *str, struct timestamp *ts)
 
298
{
 
299
 struct tm *stm;
 
300
 
 
301
 stm=localtime((time_t *)&ts->unixtime);
 
302
 /* Workaround for a MS C v 7.0 CRT bug */
 
303
 #if TARGET==DOS&&COMPILER==MSC&&_MSC_VER==700
 
304
  if(stm->tm_year<70)                   /* 31 -> 101 */
 
305
   stm->tm_year+=70;
 
306
 #endif
 
307
 sprintf(str, time_list_format, stm->tm_year+1900, stm->tm_mon+1, stm->tm_mday,
 
308
         stm->tm_hour, stm->tm_min, stm->tm_sec);
 
309
}
 
310
 
 
311
#endif