Initial import package mtools: Programs for accessing MS-DOS disks without mounting...
[profile/ivi/mtools.git] / directory.c
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  */
31 struct 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
52 int 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
79 void 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
93 struct 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  */
130 struct 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 }