📄 msdos.c
字号:
} dos_fcb;/**************************//* Function volumelabel() *//**************************/static int volumelabel(newlabel) char *newlabel;{#ifdef DEBUG char *p;#endif int len = strlen(newlabel); int fcbseg, dtaseg, fcboff, dtaoff, retv; dos_fcb fcb, dta, far *pfcb=&fcb, far *pdta=&dta; struct SREGS sregs; union REGS regs;/*--------------------------------------------------------------------------- Label the diskette specified by nLabelDrive using FCB calls. (Old ver- sions of MS-DOS and OS/2 DOS boxes can't use DOS function 3Ch to create labels.) Must use far pointers for MSC FP_* macros to work; must pad FCB filenames with spaces; and cannot include dot in 8th position. May or may not need to zero out FCBs before using; do so just in case. ---------------------------------------------------------------------------*/#ifdef WATCOMC_386 int truseg; memset(&sregs, 0, sizeof(sregs)); memset(®s, 0, sizeof(regs)); /* PMODE/W does not support extended versions of any dos FCB functions, */ /* so we have to use brute force, allocating real mode memory for them. */ regs.w.ax = 0x0100; regs.w.bx = (2 * sizeof(dos_fcb) + 15) >> 4; /* size in paragraphs */ int386(0x31, ®s, ®s); /* DPMI allocate DOS memory */ if (regs.w.cflag) return DF_MDY; /* no memory, return default */ truseg = regs.w.dx; /* protected mode selector */ dtaseg = regs.w.ax; /* real mode paragraph */ fcboff = 0; dtaoff = sizeof(dos_fcb);#ifdef XXX__MK_FP_IS_BROKEN /* XXX This code may not be trustworthy in general, though it is */ /* valid with DOS/4GW and PMODE/w, which is all we support for now. */ regs.w.ax = 6; regs.w.bx = truseg; int386(0x31, ®s, ®s); /* convert seg to linear address */ pfcb = (dos_fcb far *) (((ulg) regs.w.cx << 16) | regs.w.dx); /* pfcb = (dos_fcb far *) ((ulg) dtaseg << 4); */ pdta = pfcb + 1;#else pfcb = MK_FP(truseg, fcboff); pdta = MK_FP(truseg, dtaoff);#endif _fmemset((char far *)pfcb, 0, 2 * sizeof(dos_fcb)); /* we pass the REAL MODE paragraph to the dos interrupts: */ fcbseg = dtaseg;#else /* !WATCOMC_386 */ memset((char *)&dta, 0, sizeof(dos_fcb)); memset((char *)&fcb, 0, sizeof(dos_fcb)); fcbseg = FP_SEG(pfcb); fcboff = FP_OFF(pfcb); dtaseg = FP_SEG(pdta); dtaoff = FP_OFF(pdta);#endif /* ?WATCOMC_386 */#ifdef DEBUG for (p = (char *)&dta; (p - (char *)&dta) < sizeof(dos_fcb); ++p) if (*p) fprintf(stderr, "error: dta[%d] = %x\n", (p - (char *)&dta), *p); for (p = (char *)&fcb; (p - (char *)&fcb) < sizeof(dos_fcb); ++p) if (*p) fprintf(stderr, "error: fcb[%d] = %x\n", (p - (char *)&fcb), *p); printf("testing pointer macros:\n"); segread(&sregs); printf("cs = %x, ds = %x, es = %x, ss = %x\n", sregs.cs, sregs.ds, sregs.es, sregs.ss);#endif /* DEBUG */#if 0#ifdef __TURBOC__ bdosptr(0x1a, dta, DO_NOT_CARE);#else (intdosx method below)#endif#endif /* 0 */ /* set the disk transfer address for subsequent FCB calls */ sregs.ds = dtaseg; WREGS(regs,dx) = dtaoff; Trace((stderr, "segment:offset of pdta = %x:%x\n", dtaseg, dtaoff)); Trace((stderr, "&dta = %lx, pdta = %lx\n", (ulg)&dta, (ulg)pdta)); regs.h.ah = 0x1a; F_intdosx(®s, ®s, &sregs); /* fill in the FCB */ sregs.ds = fcbseg; WREGS(regs,dx) = fcboff; pfcb->flag = 0xff; /* extended FCB */ pfcb->vattr = 0x08; /* attribute: disk volume label */ pfcb->drive = (uch)nLabelDrive;#ifdef DEBUG Trace((stderr, "segment:offset of pfcb = %x:%x\n", sregs.ds, WREGS(regs,dx))); Trace((stderr, "&fcb = %lx, pfcb = %lx\n", (ulg)&fcb, (ulg)pfcb)); Trace((stderr, "(2nd check: labelling drive %c:)\n", pfcb->drive-1+'A')); if (pfcb->flag != fcb.flag) fprintf(stderr, "error: pfcb->flag = %d, fcb.flag = %d\n", pfcb->flag, fcb.flag); if (pfcb->drive != fcb.drive) fprintf(stderr, "error: pfcb->drive = %d, fcb.drive = %d\n", pfcb->drive, fcb.drive); if (pfcb->vattr != fcb.vattr) fprintf(stderr, "error: pfcb->vattr = %d, fcb.vattr = %d\n", pfcb->vattr, fcb.vattr);#endif /* DEBUG */ /* check for existing label */ Trace((stderr, "searching for existing label via FCBs\n")); regs.h.ah = 0x11; /* FCB find first */#ifdef WATCOMC_386 _fstrncpy((char far *)&pfcb->vn, "???????????", 11);#else strncpy((char *)fcb.vn, "???????????", 11); /* i.e., "*.*" */#endif /* ?WATCOMC_386 */ Trace((stderr, "fcb.vn = %lx\n", (ulg)fcb.vn)); Trace((stderr, "regs.h.ah = %x, regs.x.dx = %04x, sregs.ds = %04x\n", regs.h.ah, WREGS(regs,dx), sregs.ds)); Trace((stderr, "flag = %x, drive = %d, vattr = %x, vn = %s = %s.\n", fcb.flag, fcb.drive, fcb.vattr, fcb.vn, pfcb->vn)); F_intdosx(®s, ®s, &sregs);/*--------------------------------------------------------------------------- If not previously labelled, write a new label. Otherwise just rename, since MS-DOS 2.x has a bug that damages the FAT when the old label is deleted. ---------------------------------------------------------------------------*/ if (regs.h.al) { Trace((stderr, "no label found\n\n")); regs.h.ah = 0x16; /* FCB create file */#ifdef WATCOMC_386 _fstrncpy((char far *)pfcb->vn, newlabel, len); if (len < 11) _fstrncpy((char far *)(pfcb->vn+len), " ", 11-len);#else strncpy((char *)fcb.vn, newlabel, len); if (len < 11) /* fill with spaces */ strncpy((char *)(fcb.vn+len), " ", 11-len);#endif Trace((stderr, "fcb.vn = %lx pfcb->vn = %lx\n", (ulg)fcb.vn, (ulg)pfcb->vn)); Trace((stderr, "flag = %x, drive = %d, vattr = %x\n", fcb.flag, fcb.drive, fcb.vattr)); Trace((stderr, "vn = %s = %s.\n", fcb.vn, pfcb->vn)); F_intdosx(®s, ®s, &sregs); regs.h.ah = 0x10; /* FCB close file */ if (regs.h.al) { Trace((stderr, "unable to write volume name (AL = %x)\n", regs.h.al)); F_intdosx(®s, ®s, &sregs); retv = 1; } else { F_intdosx(®s, ®s, &sregs); Trace((stderr, "new volume label [%s] written\n", newlabel)); retv = 0; } } else { Trace((stderr, "found old label [%s]\n\n", dta.vn)); /* not term. */ regs.h.ah = 0x17; /* FCB rename */#ifdef WATCOMC_386 _fstrncpy((char far *)pfcb->vn, (char far *)pdta->vn, 11); _fstrncpy((char far *)pfcb->nn, newlabel, len); if (len < 11) _fstrncpy((char far *)(pfcb->nn+len), " ", 11-len);#else strncpy((char *)fcb.vn, (char *)dta.vn, 11); strncpy((char *)fcb.nn, newlabel, len); if (len < 11) /* fill with spaces */ strncpy((char *)(fcb.nn+len), " ", 11-len);#endif Trace((stderr, "fcb.vn = %lx pfcb->vn = %lx\n", (ulg)fcb.vn, (ulg)pfcb->vn)); Trace((stderr, "fcb.nn = %lx pfcb->nn = %lx\n", (ulg)fcb.nn, (ulg)pfcb->nn)); Trace((stderr, "flag = %x, drive = %d, vattr = %x\n", fcb.flag, fcb.drive, fcb.vattr)); Trace((stderr, "vn = %s = %s.\n", fcb.vn, pfcb->vn)); Trace((stderr, "nn = %s = %s.\n", fcb.nn, pfcb->nn)); F_intdosx(®s, ®s, &sregs); if (regs.h.al) { Trace((stderr, "Unable to change volume name (AL = %x)\n", regs.h.al)); retv = 1; } else { Trace((stderr, "volume label changed to [%s]\n", newlabel)); retv = 0; } }#ifdef WATCOMC_386 regs.w.ax = 0x0101; /* free dos memory */ regs.w.dx = truseg; int386(0x31, ®s, ®s);#endif return retv;} /* end function volumelabel() */#endif /* !__GO32__ && !__EMX__ */#if defined(USE_EF_UT_TIME) || defined(TIMESTAMP)/* The following DOS date/time structure is machine-dependent as it * assumes "little-endian" byte order. For MSDOS-specific code, which * is run on x86 CPUs (or emulators), this assumption is valid; but * care should be taken when using this code as template for other ports. */typedef union { ulg z_dostime;# ifdef __TURBOC__ struct ftime ft; /* system file time record */# endif struct { /* date and time words */ ush ztime; /* DOS file modification time word */ ush zdate; /* DOS file modification date word */ } zft; struct { /* DOS date/time components bitfield */ unsigned zt_se : 5; unsigned zt_mi : 6; unsigned zt_hr : 5; unsigned zd_dy : 5; unsigned zd_mo : 4; unsigned zd_yr : 7; } z_dtf;} dos_fdatetime;#endif /* USE_EF_UT_TIME || TIMESTAMP *//****************************//* Function close_outfile() *//****************************/void close_outfile(__G) __GDEF /* * MS-DOS VERSION * * Set the output file date/time stamp according to information from the * zipfile directory record for this member, then close the file and set * its permissions (archive, hidden, read-only, system). Aside from closing * the file, this routine is optional (but most compilers support it). */{#ifdef USE_EF_UT_TIME dos_fdatetime dos_dt; iztimes z_utime; struct tm *t;#endif /* USE_EF_UT_TIME *//*--------------------------------------------------------------------------- Copy and/or convert time and date variables, if necessary; then set the file time/date. WEIRD BORLAND "BUG": if output is buffered, and if run under at least some versions of DOS (e.g., 6.0), and if files are smaller than DOS physical block size (i.e., 512 bytes) (?), then files MAY NOT get timestamped correctly--apparently setftime() occurs before any data are written to the file, and when file is closed and buffers are flushed, timestamp is overwritten with current time. Even with a 32K buffer, this does not seem to occur with larger files. UnZip output is now unbuffered, but if it were not, could still avoid problem by adding "fflush(outfile)" just before setftime() call. Weird, huh? ---------------------------------------------------------------------------*/#ifdef USE_EF_UT_TIME if (G.extra_field &&#ifdef IZ_CHECK_TZ G.tz_is_valid &&#endif (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime, &z_utime, NULL) & EB_UT_FL_MTIME)) { TTrace((stderr, "close_outfile: Unix e.f. modif. time = %ld\n", z_utime.mtime)); /* round up (down if "up" overflows) to even seconds */ if (z_utime.mtime & 1) z_utime.mtime = (z_utime.mtime + 1 > z_utime.mtime) ? z_utime.mtime + 1 : z_utime.mtime - 1; TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0 or Macintosh */ t = localtime(&(z_utime.mtime)); } else t = (struct tm *)NULL; if (t != (struct tm *)NULL) { if (t->tm_year < 80) { dos_dt.z_dtf.zt_se = 0; dos_dt.z_dtf.zt_mi = 0; dos_dt.z_dtf.zt_hr = 0; dos_dt.z_dtf.zd_dy = 1; dos_dt.z_dtf.zd_mo = 1; dos_dt.z_dtf.zd_yr = 0; } else { dos_dt.z_dtf.zt_se = t->tm_sec >> 1; dos_dt.z_dtf.zt_mi = t->tm_min; dos_dt.z_dtf.zt_hr = t->tm_hour; dos_dt.z_dtf.zd_dy = t->tm_mday; dos_dt.z_dtf.zd_mo = t->tm_mon + 1; dos_dt.z_dtf.zd_yr = t->tm_year - 80; } } else { dos_dt.z_dostime = G.lrec.last_mod_dos_datetime; }# ifdef __TURBOC__ setftime(fileno(G.outfile), &dos_dt.ft);# else _dos_setftime(fileno(G.outfile), dos_dt.zft.zdate, dos_dt.zft.ztime);# endif#else /* !USE_EF_UT_TIME */# ifdef __TURBOC__ setftime(fileno(G.outfile), (struct ftime *)(&(G.lrec.last_mod_dos_datetime)));# else _dos_setftime(fileno(G.outfile), (ush)(G.lrec.last_mod_dos_datetime >> 16), (ush)(G.lrec.last_mod_dos_datetime));# endif#endif /* ?USE_EF_UT_TIME *//*--------------------------------------------------------------------------- And finally we can close the file...at least everybody agrees on how to do *this*. I think... Also change the mode according to the stored file attributes, since we didn't do that when we opened the dude. ---------------------------------------------------------------------------*/ fclose(G.outfile); z_dos_chmod(__G__ G.filename, G.pInfo->file_attr);} /* end function close_outfile() */#ifdef TIMESTAMP/*************************//* Function stamp_file() *//*************************/int stamp_file(fname, modtime) ZCONST char *fname; time_t modtime;{ dos_fdatetime dos_dt; time_t t_even; struct tm *t; int fd; /* file handle */ /* round up (down if "up" overflows) to even seconds */ t_even = ((modtime + 1 > modtime) ? modtime + 1 : modtime) & (~1); TIMET_TO_NATIVE(t_even) /* NOP unless MSC 7.0 or Macintosh */ t = localtime(&t_even); if (t == (struct tm *)NULL) return -1; /* time conversion error */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -