feat: support for IPP printing + test page
This commit is contained in:
@@ -64,7 +64,7 @@ namespace Fs {
|
||||
Ramdisk::Create,
|
||||
Ramdisk::Delete,
|
||||
Ramdisk::Mkdir,
|
||||
nullptr,
|
||||
Ramdisk::Rename,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -47,6 +47,36 @@ namespace Fs::Ramdisk {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int NormalizePath(const char* path, char* out, int outMax) {
|
||||
if (path == nullptr || out == nullptr || outMax <= 1) return -1;
|
||||
if (path[0] == '/') path++;
|
||||
|
||||
int len = 0;
|
||||
while (path[len] != '\0' && len < outMax - 1) {
|
||||
out[len] = path[len];
|
||||
len++;
|
||||
}
|
||||
out[len] = '\0';
|
||||
|
||||
while (len > 1 && out[len - 1] == '/') {
|
||||
out[--len] = '\0';
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int FindEntryByPath(const char* path) {
|
||||
char normalized[MaxNameLen];
|
||||
int normLen = NormalizePath(path, normalized, MaxNameLen);
|
||||
if (normLen < 0) return -1;
|
||||
|
||||
for (int i = 0; i < fileCount; i++) {
|
||||
char entryPath[MaxNameLen];
|
||||
NormalizePath(fileTable[i].name, entryPath, MaxNameLen);
|
||||
if (StrEqual(entryPath, normalized)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Initialize(void* moduleData, uint64_t moduleSize) {
|
||||
Kt::KernelLogStream(Kt::OK, "Ramdisk") << "Parsing USTAR archive (" << moduleSize << " bytes)";
|
||||
|
||||
@@ -405,6 +435,76 @@ namespace Fs::Ramdisk {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Rename(const char* oldPath, const char* newPath) {
|
||||
char oldNorm[MaxNameLen];
|
||||
char newNorm[MaxNameLen];
|
||||
int oldLen = NormalizePath(oldPath, oldNorm, MaxNameLen);
|
||||
int newLen = NormalizePath(newPath, newNorm, MaxNameLen);
|
||||
if (oldLen <= 0 || newLen <= 0) return -1;
|
||||
|
||||
int src = FindEntryByPath(oldNorm);
|
||||
if (src < 0) return -1;
|
||||
|
||||
int dst = FindEntryByPath(newNorm);
|
||||
if (dst >= 0 && dst != src) {
|
||||
if (Delete(newNorm) < 0) return -1;
|
||||
if (dst < src) src--;
|
||||
}
|
||||
|
||||
const bool isDirectory = fileTable[src].isDirectory;
|
||||
|
||||
if (!isDirectory) {
|
||||
if (newLen >= MaxNameLen) return -1;
|
||||
for (int i = 0; i <= newLen; i++) fileTable[src].name[i] = newNorm[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
char oldPrefix[MaxNameLen];
|
||||
if (oldLen + 1 >= MaxNameLen || newLen + 1 >= MaxNameLen) return -1;
|
||||
|
||||
for (int i = 0; i < oldLen; i++) oldPrefix[i] = oldNorm[i];
|
||||
oldPrefix[oldLen] = '/';
|
||||
oldPrefix[oldLen + 1] = '\0';
|
||||
|
||||
for (int i = 0; i < fileCount; i++) {
|
||||
char normalized[MaxNameLen];
|
||||
int normalizedLen = NormalizePath(fileTable[i].name, normalized, MaxNameLen);
|
||||
if (normalizedLen < 0) return -1;
|
||||
|
||||
bool exactMatch = StrEqual(normalized, oldNorm);
|
||||
bool childMatch = StartsWith(fileTable[i].name, oldPrefix);
|
||||
if (!exactMatch && !childMatch) continue;
|
||||
|
||||
char updated[MaxNameLen];
|
||||
if (exactMatch) {
|
||||
for (int j = 0; j <= newLen; j++) updated[j] = newNorm[j];
|
||||
} else {
|
||||
int suffixLen = StrLen(fileTable[i].name) - (oldLen + 1);
|
||||
if (newLen + 1 + suffixLen >= MaxNameLen) return -1;
|
||||
|
||||
int pos = 0;
|
||||
for (int j = 0; j < newLen; j++) updated[pos++] = newNorm[j];
|
||||
updated[pos++] = '/';
|
||||
const char* suffix = fileTable[i].name + oldLen + 1;
|
||||
while (*suffix && pos < MaxNameLen - 1) updated[pos++] = *suffix++;
|
||||
updated[pos] = '\0';
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
while (updated[pos] != '\0' && pos < MaxNameLen - 1) {
|
||||
fileTable[i].name[pos] = updated[pos];
|
||||
pos++;
|
||||
}
|
||||
if (fileTable[i].isDirectory) {
|
||||
if (pos >= MaxNameLen - 1) return -1;
|
||||
fileTable[i].name[pos++] = '/';
|
||||
}
|
||||
fileTable[i].name[pos] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetFileCount() {
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Fs::Ramdisk {
|
||||
int ReadDir(const char* path, const char** outNames, int maxEntries);
|
||||
int Delete(const char* path);
|
||||
int Mkdir(const char* path);
|
||||
int Rename(const char* oldPath, const char* newPath);
|
||||
int GetFileCount();
|
||||
|
||||
}
|
||||
|
||||
+73
-39
@@ -553,11 +553,6 @@ namespace Net::Tcp {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Phase 1: Send data segments with interrupts disabled (lock-safe)
|
||||
uint64_t flags;
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
|
||||
conn->Lock.Acquire();
|
||||
|
||||
constexpr uint16_t MSS = 1460;
|
||||
uint16_t sent = 0;
|
||||
|
||||
@@ -567,6 +562,21 @@ namespace Net::Tcp {
|
||||
segLen = MSS;
|
||||
}
|
||||
|
||||
uint32_t segSeq = 0;
|
||||
uint32_t expectedAck = 0;
|
||||
uint64_t flags;
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
|
||||
conn->Lock.Acquire();
|
||||
|
||||
if (conn->CurrentState != State::Established) {
|
||||
conn->Lock.Release();
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory");
|
||||
return sent > 0 ? sent : -1;
|
||||
}
|
||||
|
||||
segSeq = conn->SendNext;
|
||||
expectedAck = segSeq + segLen;
|
||||
|
||||
bool ok = SendSegment(conn, FLAG_ACK | FLAG_PSH, data + sent, segLen);
|
||||
if (!ok) {
|
||||
conn->Lock.Release();
|
||||
@@ -574,9 +584,8 @@ namespace Net::Tcp {
|
||||
return sent > 0 ? sent : -1;
|
||||
}
|
||||
|
||||
conn->SendNext += segLen;
|
||||
conn->SendNext = expectedAck;
|
||||
|
||||
// Store for retransmission
|
||||
if (segLen <= sizeof(conn->RetransmitBuffer)) {
|
||||
memcpy(conn->RetransmitBuffer, data + sent, segLen);
|
||||
conn->RetransmitLen = segLen;
|
||||
@@ -584,44 +593,69 @@ namespace Net::Tcp {
|
||||
conn->RetransmitCount = 0;
|
||||
}
|
||||
|
||||
sent += segLen;
|
||||
}
|
||||
conn->Lock.Release();
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory");
|
||||
|
||||
conn->Lock.Release();
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory");
|
||||
|
||||
// Phase 2: Wait for ACK without holding the lock (interrupts enabled)
|
||||
uint64_t startTime = Timekeeping::GetMilliseconds();
|
||||
while (conn->SendUnack != conn->SendNext) {
|
||||
uint64_t now = Timekeeping::GetMilliseconds();
|
||||
if ((now - startTime) > (RETRANSMIT_TIMEOUT_MS * MAX_RETRANSMITS)) {
|
||||
break;
|
||||
}
|
||||
if ((now - conn->RetransmitTime) > RETRANSMIT_TIMEOUT_MS && conn->RetransmitLen > 0) {
|
||||
conn->RetransmitCount++;
|
||||
if (conn->RetransmitCount > MAX_RETRANSMITS) {
|
||||
break;
|
||||
}
|
||||
// Retransmit with brief interrupt-disabled window
|
||||
while (true) {
|
||||
asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory");
|
||||
conn->Lock.Acquire();
|
||||
uint32_t savedNext = conn->SendNext;
|
||||
conn->SendNext = conn->SendUnack;
|
||||
SendSegment(conn, FLAG_ACK | FLAG_PSH,
|
||||
conn->RetransmitBuffer, conn->RetransmitLen);
|
||||
conn->SendNext = savedNext;
|
||||
conn->RetransmitTime = Timekeeping::GetMilliseconds();
|
||||
|
||||
if (conn->SendUnack >= expectedAck) {
|
||||
conn->RetransmitLen = 0;
|
||||
conn->Lock.Release();
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory");
|
||||
sent += segLen;
|
||||
break;
|
||||
}
|
||||
|
||||
if (conn->CurrentState != State::Established) {
|
||||
conn->SendNext = conn->SendUnack;
|
||||
conn->RetransmitLen = 0;
|
||||
conn->Lock.Release();
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory");
|
||||
return sent > 0 ? sent : -1;
|
||||
}
|
||||
|
||||
uint64_t now = Timekeeping::GetMilliseconds();
|
||||
bool shouldRetransmit =
|
||||
conn->RetransmitLen == segLen &&
|
||||
(now - conn->RetransmitTime) > RETRANSMIT_TIMEOUT_MS;
|
||||
if (shouldRetransmit) {
|
||||
conn->RetransmitCount++;
|
||||
if (conn->RetransmitCount > MAX_RETRANSMITS) {
|
||||
conn->SendNext = conn->SendUnack;
|
||||
conn->RetransmitLen = 0;
|
||||
conn->Lock.Release();
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory");
|
||||
return sent > 0 ? sent : -1;
|
||||
}
|
||||
|
||||
uint32_t savedNext = conn->SendNext;
|
||||
conn->SendNext = segSeq;
|
||||
bool retryOk = SendSegment(conn, FLAG_ACK | FLAG_PSH,
|
||||
conn->RetransmitBuffer, conn->RetransmitLen);
|
||||
conn->SendNext = savedNext;
|
||||
conn->RetransmitTime = now;
|
||||
if (!retryOk) {
|
||||
conn->SendNext = conn->SendUnack;
|
||||
conn->RetransmitLen = 0;
|
||||
conn->Lock.Release();
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory");
|
||||
return sent > 0 ? sent : -1;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t waitMs = 10;
|
||||
if (conn->RetransmitLen == segLen && now <= conn->RetransmitTime + RETRANSMIT_TIMEOUT_MS) {
|
||||
waitMs = (conn->RetransmitTime + RETRANSMIT_TIMEOUT_MS) - now;
|
||||
if (waitMs == 0) waitMs = 1;
|
||||
if (waitMs > 10) waitMs = 10;
|
||||
}
|
||||
|
||||
conn->Lock.Release();
|
||||
asm volatile("push %0; popfq" :: "r"(flags) : "memory");
|
||||
continue;
|
||||
Sched::BlockOnObject(conn, waitMs);
|
||||
}
|
||||
|
||||
uint64_t waitMs = 10;
|
||||
if (conn->RetransmitLen > 0 && now <= conn->RetransmitTime + RETRANSMIT_TIMEOUT_MS) {
|
||||
waitMs = (conn->RetransmitTime + RETRANSMIT_TIMEOUT_MS) - now;
|
||||
if (waitMs == 0) waitMs = 1;
|
||||
}
|
||||
Sched::BlockOnObject(conn, waitMs);
|
||||
}
|
||||
|
||||
return sent;
|
||||
|
||||
Reference in New Issue
Block a user