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