Skip to content

Commit b0c2187

Browse files
committed
use head instead of stack for recursive delete, avoid stack corruption on really nested directory structure
1 parent 831d2d8 commit b0c2187

File tree

1 file changed

+28
-17
lines changed

1 file changed

+28
-17
lines changed

cmd/rmdir.c

+28-17
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ int rmdir_withfiles(const char * fullname, char * path, int maxlen)
3434
int rmdir_withfiles(char * path, int maxlen)
3535
#endif
3636
{
37-
struct dos_ffblk f;
37+
struct dos_ffblk *f;
3838
int ret;
3939
int len = strlen(path); /* Warning: we assume path is a buffer is large enough for longest file path */
4040
char *p = path+len;
@@ -52,59 +52,69 @@ int rmdir_withfiles(char * path, int maxlen)
5252

5353
/* cycle through removing directories first */
5454
stpcpy(p, "*.*");
55-
if (!dos_findfirst(path, &f, FA_DIREC)) {
55+
/* allocate our findfirst/next structure on heap to avoid exhausting stack */
56+
f = (struct dos_ffblk *)malloc(sizeof(struct dos_ffblk));
57+
if (f == NULL) {
58+
error_out_of_memory();
59+
return E_NoMem;
60+
}
61+
if (!dos_findfirst(path, f, FA_DIREC)) {
5662
ret = 0;
5763
do {
5864
/* skip . and .. directory entries */
59-
if ((strcmp(f.ff_name, ".")==0) ||
60-
(strcmp(f.ff_name, "..")==0))
65+
if ((strcmp(f->ff_name, ".")==0) ||
66+
(strcmp(f->ff_name, "..")==0))
6167
continue;
6268

63-
if (f.ff_attrib & FA_DIREC) {
64-
dprintf(("name=%s\n", f.ff_name));
69+
if (f->ff_attrib & FA_DIREC) {
70+
dprintf(("name=%s\n", f->ff_name));
6571
/* avoid overflowing our buffer */
66-
if((len + strlen(f.ff_name)) > maxlen) {
72+
if((len + strlen(f->ff_name)) > maxlen) {
6773
error_filename_too_long(p);
6874
ret = E_Other;
6975
continue;
7076
}
7177

72-
strcpy(p, f.ff_name); /* Make the full path */
78+
strcpy(p, f->ff_name); /* Make the full path */
7379
/* recursively delete subdirectory */
7480
#ifdef DBCS
7581
ret = rmdir_withfiles(fullname, path, maxlen);
7682
#else
7783
ret = rmdir_withfiles(path, maxlen);
7884
#endif
7985
}
80-
} while (!ret && (dos_findnext(&f) == 0));
81-
dos_findclose(&f);
86+
} while (!ret && (dos_findnext(f) == 0));
87+
dos_findclose(f);
8288
/* return early on error */
83-
if (ret) return ret;
89+
if (ret) {
90+
free(f);
91+
return ret;
92+
}
8493
}
8594

8695
/* remove any files in current directory */
8796
stpcpy(p, "*.*");
88-
if (!dos_findfirst(path, &f, FA_NORMAL)) {
97+
if (!dos_findfirst(path, f, FA_NORMAL)) {
8998
ret = 0;
9099
do {
91100
/* avoid overflowing our buffer */
92-
if((len + strlen(f.ff_name)) > maxlen) {
101+
if((len + strlen(f->ff_name)) > maxlen) {
93102
error_filename_too_long(p);
94103
ret = E_Other;
95104
continue;
96105
}
97106

98-
strcpy(p, f.ff_name); /* Make the full path */
107+
strcpy(p, f->ff_name); /* Make the full path */
99108
dprintf(("deleting [%s]\n", path));
100109
/* try to delete the file */
101110
if(unlink(path) != 0) {
102111
myperror(path); /* notify the user */
103112
/* could exit here, but we just let rmdir fail */
104113
}
105-
} while (!ret && (dos_findnext(&f) == 0));
106-
dos_findclose(&f);
114+
} while (!ret && (dos_findnext(f) == 0));
115+
dos_findclose(f);
107116
}
117+
free(f);
108118

109119
/* finally actually remove the directory */
110120
p[-1] = '\0';
@@ -115,7 +125,8 @@ int recursive_rmdir(const char * path, int recursiveMode, int quiet)
115125
{
116126
if (recursiveMode) {
117127
struct dos_ffblk f;
118-
char fullname[MAXPATH + sizeof(f.ff_name) + 2], *p;
128+
char *p;
129+
static char fullname[MAXPATH + sizeof(f.ff_name) + 2];
119130
int len;
120131
/* Get the pattern fully-qualified */
121132
/* Note: An absolute path always contains:

0 commit comments

Comments
 (0)