1*d5c9a868SElliott Hughes /* Copyright 1995 David C. Niemi
2*d5c9a868SElliott Hughes * Copyright 1996-2002,2008,2009 Alain Knaff.
3*d5c9a868SElliott Hughes * This file is part of mtools.
4*d5c9a868SElliott Hughes *
5*d5c9a868SElliott Hughes * Mtools is free software: you can redistribute it and/or modify
6*d5c9a868SElliott Hughes * it under the terms of the GNU General Public License as published by
7*d5c9a868SElliott Hughes * the Free Software Foundation, either version 3 of the License, or
8*d5c9a868SElliott Hughes * (at your option) any later version.
9*d5c9a868SElliott Hughes *
10*d5c9a868SElliott Hughes * Mtools is distributed in the hope that it will be useful,
11*d5c9a868SElliott Hughes * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*d5c9a868SElliott Hughes * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*d5c9a868SElliott Hughes * GNU General Public License for more details.
14*d5c9a868SElliott Hughes *
15*d5c9a868SElliott Hughes * You should have received a copy of the GNU General Public License
16*d5c9a868SElliott Hughes * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
17*d5c9a868SElliott Hughes */
18*d5c9a868SElliott Hughes #include "sysincludes.h"
19*d5c9a868SElliott Hughes #include "msdos.h"
20*d5c9a868SElliott Hughes #include "stream.h"
21*d5c9a868SElliott Hughes #include "mtools.h"
22*d5c9a868SElliott Hughes #include "file.h"
23*d5c9a868SElliott Hughes #include "fs.h"
24*d5c9a868SElliott Hughes #include "file_name.h"
25*d5c9a868SElliott Hughes
26*d5c9a868SElliott Hughes /* #define DEBUG */
27*d5c9a868SElliott Hughes
28*d5c9a868SElliott Hughes /*
29*d5c9a868SElliott Hughes * Read a directory entry into caller supplied buffer
30*d5c9a868SElliott Hughes */
dir_read(direntry_t * entry,int * error)31*d5c9a868SElliott Hughes struct directory *dir_read(direntry_t *entry, int *error)
32*d5c9a868SElliott Hughes {
33*d5c9a868SElliott Hughes ssize_t n;
34*d5c9a868SElliott Hughes *error = 0;
35*d5c9a868SElliott Hughes if((n=force_pread(entry->Dir, (char *) (&entry->dir),
36*d5c9a868SElliott Hughes (mt_off_t) entry->entry * MDIR_SIZE,
37*d5c9a868SElliott Hughes MDIR_SIZE)) != MDIR_SIZE) {
38*d5c9a868SElliott Hughes if (n < 0) {
39*d5c9a868SElliott Hughes *error = -1;
40*d5c9a868SElliott Hughes }
41*d5c9a868SElliott Hughes return NULL;
42*d5c9a868SElliott Hughes }
43*d5c9a868SElliott Hughes return &entry->dir;
44*d5c9a868SElliott Hughes }
45*d5c9a868SElliott Hughes
46*d5c9a868SElliott Hughes /*
47*d5c9a868SElliott Hughes * Make a subdirectory grow in length. Only subdirectories (not root)
48*d5c9a868SElliott Hughes * may grow. Returns a 0 on success, 1 on failure (disk full), or -1
49*d5c9a868SElliott Hughes * on error.
50*d5c9a868SElliott Hughes */
51*d5c9a868SElliott Hughes
dir_grow(Stream_t * Dir,int size)52*d5c9a868SElliott Hughes int dir_grow(Stream_t *Dir, int size)
53*d5c9a868SElliott Hughes {
54*d5c9a868SElliott Hughes Stream_t *Stream = GetFs(Dir);
55*d5c9a868SElliott Hughes DeclareThis(Fs_t);
56*d5c9a868SElliott Hughes ssize_t ret;
57*d5c9a868SElliott Hughes unsigned int buflen;
58*d5c9a868SElliott Hughes char *buffer;
59*d5c9a868SElliott Hughes
60*d5c9a868SElliott Hughes if (!getfreeMinClusters(Dir, 1))
61*d5c9a868SElliott Hughes return -1;
62*d5c9a868SElliott Hughes
63*d5c9a868SElliott Hughes buflen = getClusterBytes(This);
64*d5c9a868SElliott Hughes
65*d5c9a868SElliott Hughes if(! (buffer=malloc(buflen)) ){
66*d5c9a868SElliott Hughes perror("dir_grow: malloc");
67*d5c9a868SElliott Hughes return -1;
68*d5c9a868SElliott Hughes }
69*d5c9a868SElliott Hughes
70*d5c9a868SElliott Hughes memset((char *) buffer, '\0', buflen);
71*d5c9a868SElliott Hughes ret = force_pwrite(Dir, buffer, (mt_off_t) size * MDIR_SIZE, buflen);
72*d5c9a868SElliott Hughes free(buffer);
73*d5c9a868SElliott Hughes if(ret < (int) buflen)
74*d5c9a868SElliott Hughes return -1;
75*d5c9a868SElliott Hughes return 0;
76*d5c9a868SElliott Hughes }
77*d5c9a868SElliott Hughes
78*d5c9a868SElliott Hughes
low_level_dir_write(direntry_t * entry)79*d5c9a868SElliott Hughes void low_level_dir_write(direntry_t *entry)
80*d5c9a868SElliott Hughes {
81*d5c9a868SElliott Hughes force_pwrite(entry->Dir,
82*d5c9a868SElliott Hughes (char *) (&entry->dir),
83*d5c9a868SElliott Hughes (mt_off_t) entry->entry * MDIR_SIZE, MDIR_SIZE);
84*d5c9a868SElliott Hughes }
85*d5c9a868SElliott Hughes
low_level_dir_write_end(Stream_t * Dir,int entry)86*d5c9a868SElliott Hughes void low_level_dir_write_end(Stream_t *Dir, int entry)
87*d5c9a868SElliott Hughes {
88*d5c9a868SElliott Hughes char zero = ENDMARK;
89*d5c9a868SElliott Hughes force_pwrite(Dir, &zero, (mt_off_t) entry * MDIR_SIZE, 1);
90*d5c9a868SElliott Hughes }
91*d5c9a868SElliott Hughes
92*d5c9a868SElliott Hughes /*
93*d5c9a868SElliott Hughes * Make a directory entry. Builds a directory entry based on the
94*d5c9a868SElliott Hughes * name, attribute, starting cluster number, and size. Returns a pointer
95*d5c9a868SElliott Hughes * to a static directory structure.
96*d5c9a868SElliott Hughes */
97*d5c9a868SElliott Hughes
mk_entry(const dos_name_t * dn,unsigned char attr,unsigned int fat,uint32_t size,time_t date,struct directory * ndir)98*d5c9a868SElliott Hughes struct directory *mk_entry(const dos_name_t *dn, unsigned char attr,
99*d5c9a868SElliott Hughes unsigned int fat, uint32_t size, time_t date,
100*d5c9a868SElliott Hughes struct directory *ndir)
101*d5c9a868SElliott Hughes {
102*d5c9a868SElliott Hughes struct tm *now;
103*d5c9a868SElliott Hughes time_t date2 = date;
104*d5c9a868SElliott Hughes uint8_t hour, min_hi, min_low, sec;
105*d5c9a868SElliott Hughes uint8_t year, month_hi, month_low, day;
106*d5c9a868SElliott Hughes
107*d5c9a868SElliott Hughes now = localtime(&date2);
108*d5c9a868SElliott Hughes dosnameToDirentry(dn, ndir);
109*d5c9a868SElliott Hughes ndir->attr = attr;
110*d5c9a868SElliott Hughes ndir->ctime_ms = 0;
111*d5c9a868SElliott Hughes hour = (uint8_t) (now->tm_hour << 3);
112*d5c9a868SElliott Hughes min_hi = (uint8_t) (now->tm_min >> 3);
113*d5c9a868SElliott Hughes min_low = (uint8_t) (now->tm_min << 5);
114*d5c9a868SElliott Hughes sec = (uint8_t) (now->tm_sec / 2);
115*d5c9a868SElliott Hughes ndir->ctime[1] = ndir->time[1] = hour + min_hi;
116*d5c9a868SElliott Hughes ndir->ctime[0] = ndir->time[0] = min_low + sec;
117*d5c9a868SElliott Hughes year = (uint8_t) ((now->tm_year - 80) << 1);
118*d5c9a868SElliott Hughes month_hi = (uint8_t) ((now->tm_mon + 1) >> 3);
119*d5c9a868SElliott Hughes month_low = (uint8_t) ((now->tm_mon + 1) << 5);
120*d5c9a868SElliott Hughes day = (uint8_t) (now->tm_mday);
121*d5c9a868SElliott Hughes ndir -> adate[1] = ndir->cdate[1] = ndir->date[1] = year + month_hi;
122*d5c9a868SElliott Hughes ndir -> adate[0] = ndir->cdate[0] = ndir->date[0] = month_low + day;
123*d5c9a868SElliott Hughes
124*d5c9a868SElliott Hughes set_word(ndir->start, fat & 0xffff);
125*d5c9a868SElliott Hughes set_word(ndir->startHi, fat >> 16);
126*d5c9a868SElliott Hughes set_dword(ndir->size, size);
127*d5c9a868SElliott Hughes return ndir;
128*d5c9a868SElliott Hughes }
129*d5c9a868SElliott Hughes
130*d5c9a868SElliott Hughes /*
131*d5c9a868SElliott Hughes * Make a directory entry from base name. This is supposed to be used
132*d5c9a868SElliott Hughes * from places such as mmd for making special entries (".", "..", "/", ...)
133*d5c9a868SElliott Hughes * Thus it doesn't bother with character set conversions
134*d5c9a868SElliott Hughes */
mk_entry_from_base(const char * base,unsigned char attr,unsigned int fat,uint32_t size,time_t date,struct directory * ndir)135*d5c9a868SElliott Hughes struct directory *mk_entry_from_base(const char *base, unsigned char attr,
136*d5c9a868SElliott Hughes unsigned int fat, uint32_t size, time_t date,
137*d5c9a868SElliott Hughes struct directory *ndir)
138*d5c9a868SElliott Hughes {
139*d5c9a868SElliott Hughes struct dos_name_t dn;
140*d5c9a868SElliott Hughes strncpy(dn.base, base, 8);
141*d5c9a868SElliott Hughes strncpy(dn.ext, " ", 3);
142*d5c9a868SElliott Hughes return mk_entry(&dn, attr, fat, size, date, ndir);
143*d5c9a868SElliott Hughes }
144